package com.xbongbong.pro.statistic.help;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.ChartStatisticsConstant;
import com.xbongbong.paas.constant.FieldAttrConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasFormSubDataEntity;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.ComboTypeEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.UnitEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.helper.ReflectHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.DigestUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.IntervalTypeEnum;
import com.xbongbong.pro.enums.LeaveMarksEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.datacenter.datawarning.enums.DataWarningConditionEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.label.pojo.LabelPojo;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartDtoHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.PkHelp;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.constant.ChartConstant;
import com.xbongbong.pro.statistic.enums.AdvancedComputingFirstEnum;
import com.xbongbong.pro.statistic.enums.AdvancedComputingSecondEnum;
import com.xbongbong.pro.statistic.enums.AreaTypeEnum;
import com.xbongbong.pro.statistic.enums.ChartAggResultEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.DateTypeEnum;
import com.xbongbong.pro.statistic.enums.DateWayEnum;
import com.xbongbong.pro.statistic.enums.DrillFieldEnum;
import com.xbongbong.pro.statistic.enums.LagEnum;
import com.xbongbong.pro.statistic.enums.NormalTypeEnum;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.ResultFromEnum;
import com.xbongbong.pro.statistic.enums.StatisticsTypeEnum;
import com.xbongbong.pro.statistic.enums.ValueRateEnum;
import com.xbongbong.pro.statistic.enums.ValueTypeEnum;
import com.xbongbong.pro.statistic.enums.YearChainEnum;
import com.xbongbong.pro.statistic.factory.ChartAnalysisFactory;
import com.xbongbong.pro.statistic.help.strategy.field.FieldAnalysisContext;
import com.xbongbong.pro.statistic.model.ChartCategoryModel;
import com.xbongbong.pro.statistic.model.ChartCustomModel;
import com.xbongbong.pro.statistic.model.ChartModel;
import com.xbongbong.pro.statistic.pojo.ChartFieldAttrPojo;
import com.xbongbong.pro.statistic.pojo.DwHistoryDataPojo;
import com.xbongbong.pro.statistic.pojo.DwTriggerConditionPojo;
import com.xbongbong.pro.statistic.pojo.FieldAnalysisPojo;
import com.xbongbong.pro.statistic.pojo.dto.ChartSubFormListBaseDTO;
import com.xbongbong.pro.statistic.pojo.dto.DataWarningQueryDTO;
import com.xbongbong.pro.statistic.pojo.vo.DataWarningQueryListVO;
import com.xbongbong.pro.statistic.pojo.vo.DataWarningQueryVO;
import com.xbongbong.pro.statistic.result.pojo.ChartDrillInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartIdPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartRlWarningDataPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartRlWarningPojo;
import com.xbongbong.pro.statistic.result.pojo.DrillResultChartFieldInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.DrillResultChartInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.DrillResultPojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartPenetrateResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.DiyResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.DiyResultDTO;
import com.xbongbong.pro.statistic.service.DataWarningService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.DistributorAreaEntity;
import com.xbongbong.saas.domain.entity.ProductCategoryEntity;
import com.xbongbong.saas.domain.entity.ext.WorkOrderExplainEntityExt;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.model.DistributorAreaModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.saas.model.ProductCategoryModel;
import com.xbongbong.saas.model.WorkOrderExplainModel;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * 图表结果回显公共方法
 * @author xinpeng.jiang
 * @date 2021/11/1 19:12
 * @version 1.0
 * @since V1.0
 */
@Component
public class ChartResultHelp {
    private static final Logger LOG = LoggerFactory.getLogger(ChartResultHelp.class);
    @Resource
    private ChartCategoryModel chartCategoryModel;
    @Resource
    private ChartModel chartModel;
    @Resource
    private ChartCustomModel chartCustomModel;
    @Resource
    private DataWarningService dataWarningService;
    @Resource
    private DistributorAreaModel distributorAreaModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private FieldAnalysisContext fieldAnalysisContext;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private UserModel userModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private ChartDtoHelp chartDtoHelp;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private PkHelp pkHelp;
    @Resource
    private WorkOrderExplainModel workOrderExplainModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private ProductCategoryModel productCategoryModel;
    @Resource
    private CustomHelp customHelp;
    @Resource
    private LinkageHelp linkageHelp;
    /**
     * 子表单字段特殊处理
     *
     * @param fieldAttrPojo 字段属性
     * @param values        值的集合
     * @param chartEntity   图表详情
     * @throws XbbException error
     * @author yuqian
     * @date 2019/6/3 17:37
     */
    public Map<String, String> getSubFormMap(FieldAttrPojo fieldAttrPojo, List<String> values, ChartEntity chartEntity, BaseDTO baseDTO) throws XbbException {
        Map<String, String> parseValueMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        SubFormPoJo subFormPoJo = fieldAttrPojo.getSubForm();
        List<FieldAttrPojo> subFormArray = JSON.parseArray(JSON.toJSONString(subFormPoJo.getItems()), FieldAttrPojo.class);
        Map<String,Map<String,String>> parseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < subFormArray.size(); i++) {
            //第i列数据
            FieldAttrPojo subFormAttr = subFormArray.get(i);
            String subAttr = subFormAttr.getAttr();
            //数据集返回的含“.”
            if(StringUtil.isNotEmpty(subAttr)){
                if(subAttr.contains(XbbConstant.POINT)){
                    String[] subAttrArray = subAttr.split("\\.");
                    subAttr = subAttrArray[1];
                }
            }
            Integer subType = subFormAttr.getFieldType();
            List<String> colSubValue = new ArrayList<>();
            if (CollectionsUtil.isNotEmpty(values)) {
                for (String value : values) {
                    JSONArray orginValueArray = new JSONArray();
                    if (StringUtil.isNotEmpty(value)) {
                        orginValueArray = JSONArray.parseArray(value);
                    }
                    //遍历子表单
                    for (int x = 0; x < orginValueArray.size(); x++) {
                        JSONObject orginValueJson;
                        Object v = orginValueArray.get(x);
                        if(v instanceof String){
                            orginValueJson = JSONObject.parseObject(v.toString());
                        }else {
                            orginValueJson = orginValueArray.getJSONObject(x);
                        }
                        String valueSubForm = null;
                        if ((orginValueJson.get(subAttr) instanceof List) || orginValueJson.get(subAttr) instanceof JSONArray) {
                            List list = orginValueJson.getObject(subAttr, List.class);
                            StringBuilder str = new StringBuilder();
                            if (list != null && list.size() > 0) {
                                for (Object obj : list) {
                                    str.append(obj).append(",");
                                }
                                if (str.length() > 0) {
                                    str.deleteCharAt(str.length() - 1);
                                }
                            }
                            valueSubForm = str.toString();
                        } else if ((orginValueJson.get(subAttr) instanceof Map)) {
                            valueSubForm = JSONObject.toJSONString(orginValueJson.get(subAttr));
                        } else {
                            valueSubForm = orginValueJson.getString(subAttr);
                        }
                        colSubValue.add(valueSubForm);
                    }
                }
                Map<String, String> subMap = valueListAnalysis(subFormAttr, chartEntity.getCorpid(), colSubValue, chartEntity, false, null, false, baseDTO,null);
                parseMap.put(subAttr + "&" + subType, subMap);
            }
        }
        if (CollectionsUtil.isNotEmpty(values)) {
            for (String value : values) {
                JSONArray jsonObject = new JSONArray();
                if (StringUtil.isNotEmpty(value)) {
                    jsonObject = JSONArray.parseArray(value);
                }
                JSONArray parseArray = new JSONArray();
                for (int x = 0; x < jsonObject.size(); x++) {
                    JSONObject parseJson = new JSONObject();
                    JSONObject itemJson;
                    Object v = jsonObject.get(x);
                    if(v instanceof String){
                        itemJson = JSONObject.parseObject(v.toString());
                    }else {
                        itemJson = jsonObject.getJSONObject(x);
                    }
                    for (int i = 0; i < subFormArray.size(); i++) {
                        FieldAttrPojo subFormAttr = subFormArray.get(i);
                        String attr = subFormAttr.getAttr();
                        //数据集返回的含“.”
                        if(StringUtil.isNotEmpty(attr)){
                            if(attr.contains(XbbConstant.POINT)){
                                String[] subAttrArray = attr.split("\\.");
                                attr = subAttrArray[1];
                            }
                        }
                        String subAttr = attr + "&" + subFormAttr.getFieldType();
                        Map<String, String> subParseMap = parseMap.get(subAttr);
                        StringBuilder stringBuilder = new StringBuilder();
                        //取出来看有没有还抱着值
                        JSONArray formatArray = null;
                        String orginValue = null;
                        String parseValue = null;
                        if (itemJson.get(attr) instanceof List) {
                            formatArray = itemJson.getJSONArray(attr);
                            for (int j = 0; j < formatArray.size(); j++) {
                                orginValue = formatArray.getString(j);
                                parseValue = subParseMap.get(orginValue);
                                stringBuilder.append(parseValue);
                                if (j != formatArray.size() - 1) {
                                    stringBuilder.append(",");
                                }
                            }
                            parseValue = stringBuilder.toString();
                        } else {
                            orginValue = itemJson.getString(attr);
                            parseValue = subParseMap.get(orginValue);
                        }
                        parseJson.put(subAttr, parseValue);
                    }
                    parseArray.add(parseJson);
                }
                parseValueMap.put(value, parseArray.toJSONString());
            }
        }
        return parseValueMap;
    }

    /**
     * 单独装载DataMap
     *
     * @param values
     * @return
     * @author yuqian
     */
    public Map<String, String> assembleDataMap(List<String> values) {
        Map<String, String> dataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (String str : values) {
            String value = str;
            if (value != null && value.length() > 0) {
                if (value.startsWith(ChartConstant.LEFT_PARENTHESES)) {
                    value = value.substring(1);
                }
                if (value.endsWith(ChartConstant.RIGHT_PARENTHESES)) {
                    value = value.substring(0, value.length() - 1);
                }
                value = value.replaceAll("\"", "");
            }
            dataMap.put(str, value);
        }
        return dataMap;
    }

    /**
     * 获取经销商地区map
     * @param corpid
     * @return
     */
    public Map<String,String> distributorAreaMap(String corpid) {
        Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        map.put("corpid",corpid);
        map.put("del",0);
        Map<String,String> areaMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<DistributorAreaEntity> distributorAreaEntityList = distributorAreaModel.findEntities(map);
        for (DistributorAreaEntity entity : distributorAreaEntityList){
            areaMap.put(entity.getId().toString(),entity.getName());
        }
        return areaMap;
    }

    /**
     * 字段对应解析
     * 统计表查询多业务关联的时候没办法直接难道关联隐藏,在查一次
     * @param field        字段属性
     * @param corpId       公司ID
     * @param values       字段值
     * @param chartEntity  图表实体
     * @param isChart      图和表的判断标记 true为图或统计表 false为查询表
     * @param dataIdToEsId 团队查询中需要的父EsId和dataID关系对应
     * @return value字段值对应的字段解析内容
     * @author zhouwq
     * @date 2019/4/15 17:03
     */
    public Map<String, String> valueListAnalysis(FieldAttrPojo field, String corpId, List<String> values, ChartEntity chartEntity,
                                                  Boolean isChart, Map<String, String> dataIdToEsId, Boolean isGroupField, BaseDTO baseDTO,Boolean isWarningSync) throws XbbException{
        Map<String, String> results = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<String> valueResults = new ArrayList<>();
        Integer fieldType = field.getFieldType();
        Integer amountFlag = field.getAmountFlag();
        Integer integerOnly = field.getIntegerOnly();
        Integer businessType = field.getBusinessType();
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldType);
        if (values.size() > 0) {
            values.forEach(value -> {
                String result = "";
                //value为null时给空字符串
                if (Objects.nonNull(value)) {
                    result = ((ChartConstant.LEFT_PARENTHESES + ChartConstant.RIGHT_PARENTHESES).equals(value)) ? "" : value;
                }
                //处理ES查询数字返回为double类型的数据
                String splitStr = ".0";
                String splitTwoStr = ".00";
                if (result.endsWith(splitStr)) {
                    result = result.substring(0, result.length() - 2);
                } else if (result.endsWith(splitTwoStr)) {
                    result = result.substring(0, result.length() - 3);
                }
                if (Objects.equals(1, integerOnly)) {
                    field.setAccuracy(BasicConstant.ZERO);
                }
                // 金额字段展示处理（默认千分位展示）
                if (Objects.equals(1, amountFlag)) {
                    if (StringUtil.isEmpty(result)) {
                        result = "0.0";
                    }
                    if (field.getGroupingUsed() == null) {
                        // 未设置时默认千分位？还是刷数据？
                        field.setGroupingUsed(1);
                    }
                }
                valueResults.add(result);
            });
            if (fieldTypeEnum != null) {
                FieldAnalysisPojo fieldAnalysisPojo = new FieldAnalysisPojo(chartEntity, values, valueResults, field, dataIdToEsId, corpId, isGroupField, isChart, businessType, isWarningSync);
                BeanUtil.copyProperties(baseDTO, fieldAnalysisPojo);
                fieldAnalysisContext.initStrategy(fieldTypeEnum);
                results = fieldAnalysisContext.strategyMethod(fieldAnalysisPojo);
            } else {
                for (int i = 0; i < values.size(); i++) {
                    results.put(values.get(i), valueResults.get(i));
                }
            }
        }
        //将结果集合中的key置为初始传进来的values
        for (int i = 0; i < valueResults.size(); i++) {
            String value = values.get(i);
            String valueResult = results.remove(valueResults.get(i));
            if (value != null && valueResult != null) {
                results.put(value, valueResult);
            }
        }
        return results;
    }


    /**
     * 查询表数据解析
     *
     * @param resultCol
     * @param explainList
     * @return
     * @author yuqian
     */
    public JSONArray queryTableAssemble(List<List<String>> resultCol, List<JSONObject> explainList,JSONArray rowExplain) {
        JSONArray cellsList = new JSONArray();
        int width = resultCol.size();
        int length = 0;
        if (CollectionsUtil.isNotEmpty(resultCol)) {
            length = resultCol.get(0).size();
        }
        //先遍历二维数组高度
        for (int i = 0; i < length; i++) {
            JSONObject cells = new JSONObject();
            for (int j = 0; j < width; j++) {
                List<String> list = resultCol.get(j);
                JSONObject jsonObject = explainList.get(j);
                Iterator<Map.Entry<String, Object>> it = jsonObject.entrySet().iterator();
                Map.Entry<String, Object> mapEntry = null;
                if (it.hasNext()) {
                    mapEntry = it.next();
                }
                if (mapEntry != null) {
                    Object value = mapEntry.getValue();
                    String key = mapEntry.getKey();
                    String[] splitKey = key.split("&");
                    String type = null;
                    if (BasicConstant.TWO.equals(splitKey.length)) {
                        type = splitKey[1];
                    }else if(BasicConstant.ONE.equals(splitKey.length)){
                        type = rowExplain.getJSONObject(j).getString("fieldType");
                    } else {
                        type = splitKey[2];
                    }
                    Map<String, String> map = null;
                    if (value instanceof Map) {
                        map = (Map<String, String>) value;
                    }
                    String parseValue = null;
                    if (map != null) {
                        if (FieldTypeEnum.CHECKBOX_GROUP.getEsalias().equals(FieldTypeEnum.getFieldTypeEnum(Integer.valueOf(type)).getEsalias()) && !Objects.equals(FieldTypeEnum.LABEL.getType(), Integer.valueOf(type))) {
                            JSONObject explain = rowExplain.getJSONObject(j);
                            if(explain != null && ComboTypeEnum.LINKFORM.getType().equals(explain.getInteger("comboType"))){
                                StringBuilder stringBuilder = new StringBuilder();
                                if (Objects.nonNull(list.get(i))) {
                                    String[] values = list.get(i).split(",");
                                    for (int x = 0; x < values.length; x++) {
                                        stringBuilder.append(values[x] + ",");
                                    }
                                    stringBuilder.deleteCharAt(stringBuilder.length() - 1);
                                }
                                parseValue = stringBuilder.toString();

                            }else{
                                StringBuilder stringBuilder = new StringBuilder();
                                if (Objects.nonNull(list.get(i))) {
                                    String[] values = list.get(i).split(",");
                                    for (int x = 0; x < values.length; x++) {
                                        if (stringBuilder.length() != 0){
                                            stringBuilder.append(",");
                                        }
                                        String str = map.get(values[x]);
                                        stringBuilder.append(str == null ? values[x] : str);
                                    }
                                }
                                parseValue = stringBuilder.toString();
                            }
                        } else if (Objects.equals(FieldTypeEnum.LABEL.getType(), Integer.valueOf(type))) {
                            JSONArray label = new JSONArray();
                            if (Objects.nonNull(list.get(i))) {
                                String[] values = list.get(i).split(",");
                                for (int x = 0; x < values.length; x++) {
                                    if (Objects.nonNull(map.get(values[x]))) {
                                        label.add(JSON.parseObject(map.get(values[x]), LabelPojo.class));
                                    }
                                }
                            }
                            parseValue = JSON.toJSONString(label);
                        }else {
                            String result = list.get(i);
                            if (result != null && !Objects.equals(result, "")) {
                                parseValue = map.get(list.get(i));
                            } else if(Objects.equals(Integer.valueOf(type), FieldTypeEnum.SWITCH.getType())) {
                                parseValue = "否";
                            } else {
                                parseValue = "";
                            }
                        }
                    }
                    JSONArray parseJson = null;
                    boolean jsonFlag = false;
                    if (StringUtil.isNotEmpty(parseValue)) {
                        try {
                            parseJson = JSONArray.parseArray(parseValue);
                            jsonFlag = true;
                        } catch (Exception e) {
                        }
                    }
                    if (jsonFlag) {
                        cells.put(key, parseJson);
                    } else {
                        cells.put(key, parseValue);
                    }
                }

            }
            cellsList.add(cells);
        }
        return cellsList;
    }

    /**
     * 获取图表的预警
     * @param baseDTO
     * @param chartEntity
     * @return
     */
    public Map<String,Object> getDWQueryListVO(BaseDTO baseDTO, ChartEntity chartEntity) throws XbbException {
        DataWarningQueryListVO dataWarningQueryListVO;
        Map<String,Object> resultMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!(Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_STATISTICS_TABLE.getCode()) || Objects.equals(chartEntity.getChartType(),ChartTypeEnum.TARGET_CHART.getCode()) || Objects.equals(chartEntity.getChartType(),ChartTypeEnum.SECOND_TARGET_CHART.getCode()) || Objects.equals(chartEntity.getChartType(),ChartTypeEnum.LINE_CHART.getCode()) || Objects.equals(chartEntity.getChartType(),ChartTypeEnum.BAR_CHART.getCode()))){
            return null;
        }
        String key = "";
        // 获取此图表的预警设置以及预警历史
        dataWarningQueryListVO = dataWarningService.queryByChartId(new DataWarningQueryDTO(){{
            setCorpid(baseDTO.getCorpid());
            setChartId(chartEntity.getId());
        }});

        // 过滤预警设置和现在图表所得的值是不一样的预警
        Iterator<DataWarningQueryVO> iterator = dataWarningQueryListVO.getDataWarningQueryVOList().iterator();
        while(iterator.hasNext()){
            DataWarningQueryVO item = iterator.next();
            // triggerCondition是否是当前图表的值
            DwTriggerConditionPojo conditionPojo = item.getTriggerCondition().toJavaList(DwTriggerConditionPojo.class).get(0);
            FieldAttrEntity attrEntity = new FieldAttrEntity();
            List<FieldAttrEntity> fieldAttrEntityList = new ArrayList<>();
            if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.LINE_CHART.getCode()) || Objects.equals(chartEntity.getChartType(),ChartTypeEnum.BAR_CHART.getCode())){
                fieldAttrEntityList = JSONArray.parseArray(chartEntity.getChartValue().toJSONString(),FieldAttrEntity.class);
                attrEntity = JSONArray.parseArray(chartEntity.getChartValue().toJSONString(),FieldAttrEntity.class).get(0);
            }else if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.DATA_STATISTICS_TABLE.getCode()))
            {
                fieldAttrEntityList = JSONArray.parseArray(chartEntity.getSummaryAttr().toJSONString(),FieldAttrEntity.class);
            }else if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.BIAXIAL_CHART.getCode()))
            {
                JSONArray chartValue = chartEntity.getChartValue();
                JSONArray chartValueSecond = chartEntity.getChartValueSecond();
                if (CollectionUtils.isNotEmpty(chartValue)){
                    fieldAttrEntityList = JSONArray.parseArray(chartValue.toJSONString(),FieldAttrEntity.class);
                }
                if (CollectionUtils.isNotEmpty(chartValueSecond)){
                    fieldAttrEntityList.addAll(JSONArray.parseArray(chartValueSecond.toJSONString(),FieldAttrEntity.class));
                }
                fieldAttrEntityList = JSONArray.parseArray(chartEntity.getChartValue().toJSONString(),FieldAttrEntity.class);
            }else {
                attrEntity = JSONArray.parseArray(chartEntity.getSummaryAttr().toJSONString(),FieldAttrEntity.class).get(0);
            }

            if (key.isEmpty() && Objects.equals(chartEntity.getChartType(),ChartTypeEnum.TARGET_CHART.getCode())){
                key = attrEntity.getAttr() + "&" + attrEntity.getFieldType();
                resultMap.put("key",key);
            }
            if (CollectionUtils.isNotEmpty(fieldAttrEntityList)){
                Boolean removeFlag = true;
                for (FieldAttrEntity entity : fieldAttrEntityList) {
                    if ((Objects.equals(conditionPojo.getAttr(), entity.getAttr()) ||Objects.equals(conditionPojo.getAttr(), entity.getOriginalAttr())) && Objects.equals(conditionPojo.getFormId(), entity.getFormId())){
                        removeFlag = false;
                        break;
                    }
                }
                if (removeFlag){
                    iterator.remove();
                    continue;
                }
            }else if (!(Objects.equals(conditionPojo.getAttr(),attrEntity.getAttr()) && Objects.equals(conditionPojo.getFormId(), attrEntity.getFormId()))){
                iterator.remove();
                continue;
            }
        }
        resultMap.put("dataWarningQueryListVO",dataWarningQueryListVO);
        return resultMap;
    }

    /**
     * 获取系列对应的预警值Map
     * @param dataWarningQueryListVO
     * @param chartEntity
     * @param xAxisKeys
     */
    public Map<String,List<ChartRlWarningPojo>> getLegendRlWarningMap(DataWarningQueryListVO dataWarningQueryListVO, ChartEntity chartEntity, List<String> xAxisKeys){
        JSONArray summaryAttr = chartEntity.getSummaryAttr();
        // 数据预警id对应的触发条件的预警值
        Map<Long,List<BigDecimal>> dataWarningIdValueMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (null != dataWarningQueryListVO && null != dataWarningQueryListVO.getDataWarningQueryVOList()){
            dataWarningQueryListVO.getDataWarningQueryVOList().forEach(item ->{
                List<DwTriggerConditionPojo> dwTriggerConditionPojoList = item.getTriggerCondition().toJavaList(DwTriggerConditionPojo.class);
                if (CollectionUtils.isNotEmpty(dwTriggerConditionPojoList)){
                    dataWarningIdValueMap.put(item.getId(),dwTriggerConditionPojoList.get(0).getValue());
                }
            });
        }
        // 数据预警返回的数据不为null
        Map<String,List<DwHistoryDataPojo>> legendHisDataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,List<ChartRlWarningPojo>> legendRlWarningMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (null != dataWarningQueryListVO && null != dataWarningQueryListVO.getDataWarningQueryVOList()){
            //预警颜色warningIdColorMaps
            Map<Long, String> warningIdColorMaps = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 获取预警对应的颜色和系列对应的历史预警值
            Iterator<DataWarningQueryVO> iterator = dataWarningQueryListVO.getDataWarningQueryVOList().iterator();
            while(iterator.hasNext()){
                DataWarningQueryVO item = iterator.next();
                // 系列对应的历史预警值加载
                for (DwHistoryDataPojo pojo : item.getDwHistoryDataList()) {
                    pojo.setDataWarningId(item.getId());
                    if (legendHisDataMap.containsKey(pojo.getLegendKey())){
                        legendHisDataMap.put(pojo.getLegendKey(),new ArrayList<DwHistoryDataPojo>(){{addAll(legendHisDataMap.get(pojo.getLegendKey()));add(pojo);}});
                    }else {
                        legendHisDataMap.put(pojo.getLegendKey(),new ArrayList<DwHistoryDataPojo>(){{add(pojo);}});
                    }
                }
                // 获取预警对应的颜色
                if(!warningIdColorMaps.containsKey(item.getId())){
                    warningIdColorMaps.put(item.getId(),item.getColor());
                }
            }
            // 系列对应的预警值Map（还根据预警设置不同分了一层，所以用Map,用上面得到的系列对应的预警值legendHisDataMap来处理）
            legendRlWarningMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (Map.Entry<String, List<DwHistoryDataPojo>> entry : legendHisDataMap.entrySet()) {
                String k = entry.getKey();
                List<DwHistoryDataPojo> v = entry.getValue();
                // 预警id对应的预警值
                Map<Long, List<DwHistoryDataPojo>> warningIdDataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                v.forEach(item -> {
                    if (warningIdDataMap.containsKey(item.getDataWarningId())) {
                        warningIdDataMap.put(item.getDataWarningId(), new ArrayList<DwHistoryDataPojo>() {{
                            addAll(warningIdDataMap.get(item.getDataWarningId()));
                            add(item);
                        }});
                    } else {
                        warningIdDataMap.put(item.getDataWarningId(), new ArrayList<DwHistoryDataPojo>() {{
                            add(item);
                        }});
                    }
                });

                // 当前循环到的这个系列的预警值（用于前端渲染）
                List<ChartRlWarningPojo> pojoList = new ArrayList<>();

                warningIdDataMap.forEach((k2, v2) -> {
                    pojoList.add(new ChartRlWarningPojo() {{
                        // 加载预警id，颜色和预警值
                        setId(k2);
                        setColor(warningIdColorMaps.get(k2));
                        setValues(dataWarningIdValueMap.get(k2));
                        // 这个系列里面这个预警id的预警值
                        List<ChartRlWarningDataPojo> warningDataList = new ArrayList<>();
                        v2.forEach(pojo -> {
                            boolean isWarning;
                            //                            if (Objects.equals(chartEntity.getMuti(),0) && Objects.equals(getLeastTriggerTime(), pojo.getDwTriggerTime())) {
                            //                                isWarning = true;
                            //                            }else {
                            isWarning = false;
                            //                            }
                            int index = xAxisKeys.indexOf(pojo.getXAxisKey());
                            warningDataList.add(new ChartRlWarningDataPojo(){{
                                setTime(pojo.getTriggerTime());
                                setValue(pojo.getWarnValue());
                                setWarning(isWarning);
                                setIndex(index);

                            }});
                        });
                        setData(warningDataList);
                    }});
                });
                legendRlWarningMap.put(k, pojoList);
            }
        }
        return legendRlWarningMap;
    }

    /**
     * 柱形图和折现图单表的当前预警要实时查询
     * @param dataWarningQueryListVO
     * @param chartEntity
     * @param warningIdWarningPojoMap
     */
    public Map<Long,ChartRlWarningPojo> getBLWarning(DataWarningQueryListVO dataWarningQueryListVO,ChartEntity chartEntity,int index,Map<Long,ChartRlWarningPojo> warningIdWarningPojoMap,String dataValue, FieldAttrPojo fieldAttrPojo){
        // 数据预警id对应的触发条件的预警值
        Map<Long,List<BigDecimal>> dataWarningIdValueMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (null != dataWarningQueryListVO && null != dataWarningQueryListVO.getDataWarningQueryVOList()){
            dataWarningQueryListVO.getDataWarningQueryVOList().forEach(item ->{
                List<DwTriggerConditionPojo> dwTriggerConditionPojoList = item.getTriggerCondition().toJavaList(DwTriggerConditionPojo.class);
                if (CollectionUtils.isNotEmpty(dwTriggerConditionPojoList)){
                    dataWarningIdValueMap.put(item.getId(),dwTriggerConditionPojoList.get(0).getValue());
                }
            });
        }
        // 预警的当前预警要实时查询
        if(null != dataWarningQueryListVO && null != dataWarningQueryListVO.getDataWarningQueryVOList()){
            for (DataWarningQueryVO item : dataWarningQueryListVO.getDataWarningQueryVOList()) {
                List<DwTriggerConditionPojo> triggerConditionList = item.getTriggerCondition().toJavaList(DwTriggerConditionPojo.class);
                DwTriggerConditionPojo dwTriggerConditionPojo;
                if (CollectionUtils.isNotEmpty(triggerConditionList)){
                    dwTriggerConditionPojo = triggerConditionList.get(0);
                    if (!(Objects.equals(dwTriggerConditionPojo.getAttr(),fieldAttrPojo.getAttr()) || Objects.equals(dwTriggerConditionPojo.getAttr(),fieldAttrPojo.getOriginalAttr())) || !Objects.equals(dwTriggerConditionPojo.getFormId(),fieldAttrPojo.getFormId())){
                        continue;
                    }
                }
                if (checkIsTrigger(item.getTriggerCondition(), dataValue)){
                    if (warningIdWarningPojoMap.containsKey(item.getId())){
                        ChartRlWarningDataPojo dataPojo = new ChartRlWarningDataPojo();
                        dataPojo.setWarning(true);
                        dataPojo.setIndex(index);
                        dataPojo.setValue(new BigDecimal(dataValue.replaceAll(",","").replaceAll("%","")));
                        ChartRlWarningPojo chartRlWarningPojo = warningIdWarningPojoMap.get(item.getId());
                        chartRlWarningPojo.setData(new ArrayList<ChartRlWarningDataPojo>(){{addAll(chartRlWarningPojo.getData());add(dataPojo);}});
                        warningIdWarningPojoMap.put(item.getId(),chartRlWarningPojo);
                    }else {
                        ChartRlWarningDataPojo dataPojo = new ChartRlWarningDataPojo();
                        dataPojo.setWarning(true);
                        dataPojo.setIndex(index);
                        dataPojo.setValue(new BigDecimal(dataValue.replaceAll(",","").replaceAll("%","")));
                        ChartRlWarningPojo chartRlWarningPojo = new ChartRlWarningPojo();
                        chartRlWarningPojo.setValues(dataWarningIdValueMap.get(item.getId()));
                        chartRlWarningPojo.setId(item.getId());
                        chartRlWarningPojo.setColor(item.getColor());
                        chartRlWarningPojo.setData(new ArrayList<ChartRlWarningDataPojo>(){{add(dataPojo);}});
                        warningIdWarningPojoMap.put(item.getId(),chartRlWarningPojo);
                    }
                }else if (!warningIdWarningPojoMap.containsKey(item.getId())){
                    ChartRlWarningPojo chartRlWarningPojo = new ChartRlWarningPojo();
                    chartRlWarningPojo.setData(new ArrayList<>());
                    chartRlWarningPojo.setValues(dataWarningIdValueMap.get(item.getId()));
                    chartRlWarningPojo.setId(item.getId());
                    chartRlWarningPojo.setColor(item.getColor());
                    warningIdWarningPojoMap.put(item.getId(),chartRlWarningPojo);
                }
            }
        }
        return warningIdWarningPojoMap;
    }
    /**
     *  通过返回的数据，判断当前这个预警设置是否被触发了。
     * @return
     */
    public boolean checkIsTrigger(JSONArray triggerCondition,String dataValue) {
        if (Objects.nonNull(triggerCondition) && Objects.nonNull(dataValue) && !dataValue.isEmpty()) {
            List<DwTriggerConditionPojo> triggerConditionPojos = triggerCondition.toJavaList(DwTriggerConditionPojo.class);
            for (DwTriggerConditionPojo pojo : triggerConditionPojos) {
                String symbol = pojo.getSymbol();
                List<BigDecimal> value = pojo.getValue();
                if (CollectionUtils.isEmpty(value)){
                    return false;
                }
                BigDecimal firstValue = value.get(0);
                DataWarningConditionEnum conditionEnum = DataWarningConditionEnum.getBySymbol(symbol);
                BigDecimal dataNumberValue = new BigDecimal(0);
                if (dataValue.charAt(dataValue.length()-1) == '&'){
                    firstValue = firstValue.multiply(new BigDecimal("100"));
                }
                if (isNumber(dataValue = dataValue.replaceAll(",","").replaceAll("%",""))){
                    dataNumberValue = new BigDecimal(dataValue);
                }else {
                    return false;
                }

                switch (conditionEnum) {
                    case GREATEREQUAL:
                        if (dataNumberValue.compareTo(firstValue) >= 0) {
                            return true;
                        }
                        break;
                    case GREATERTHAN:
                        if (dataNumberValue.compareTo(firstValue) > 0) {
                            return true;
                        }
                        break;
                    case LESSEQUAL:
                        if (dataNumberValue.compareTo(firstValue) <= 0) {
                            return true;
                        }
                        break;
                    case LESSTHAN:
                        if (dataNumberValue.compareTo(firstValue) < 0) {
                            return true;
                        }
                        break;
                    case RANGE:
                        if (value.size() == PaasConstant.RANGE_SIZE && dataNumberValue.compareTo(firstValue) >= 0 && dataNumberValue.compareTo(value.get(1)) < 0) {
                            return true;
                        }
                        break;
                    default:
                        return false;
                }
            }
        }
        return false;
    }

    public static boolean isNumber(String str){
        String reg = "^[0-9]+(.[0-9]+)?$";
        return str.matches(reg);
    }


    /**
     * 同环比判断
     * @param dateFieldAttrPojo 日期字段
     * @param advancedComputing 高级条件
     * @return
     */
    public boolean isYearChain4Date(FieldAttrPojo dateFieldAttrPojo, JSONArray advancedComputing) {
        return EsUtil.isDateByEsalias(dateFieldAttrPojo) && advancedComputing != null && Objects.equals(advancedComputing.getString(0), AdvancedComputingFirstEnum.YEAR_CHAIN.getAlias()) && advancedComputing.size() > 1;
    }

    /**
     * 同（环）期值计算——统计图（除指标图）
     * @param xAxisKeys x轴数据
     * @param xAxis x轴
     * @param jsonArrayMap 结果集
     * @param chartType
     * @param classifyAttr y轴
     * @param legendContrast
     * @param advancedComputing 高级计算条件
     * @param index
     * @param fieldType
     * @return java.lang.String
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/7/20 17:21
     * @version 1.0
     */
    public String getOldValue4Chart(List<String> xAxisKeys, List<String> xAxis, Map<String, JSONObject> jsonArrayMap, Integer chartType, FieldAttrPojo classifyAttr, String legendContrast, JSONArray advancedComputing, int index, Integer fieldType) {
        String oldVal = "";
        try {
            // 获取相差的桶数
            int yearChainDiff = getYearChainDiff(chartType, classifyAttr, advancedComputing, Long.parseLong(xAxisKeys.get(index))).intValue();
            if (yearChainDiff > 0) {
                int diffIndex = index - yearChainDiff;
                JSONObject diffObj = null;
                try {
                    diffObj = jsonArrayMap.get(xAxis.get(diffIndex) + "-" + legendContrast);
                } catch (IndexOutOfBoundsException e) {
                    // 走到这，代表不存在差值，oldVal保持为""即可
                }
                if (Objects.nonNull(diffObj)) {
                    if (fieldType.equals(FieldTypeEnum.COUNT.getType())) {
                        oldVal = diffObj.getString(ChartAggResultEnum.DOC_COUNT.getStr());
                    } else {
                        oldVal = diffObj.getString(ChartAggResultEnum.COUNT.getStr());
                    }
                }
            }
        } catch (Exception e) {
            LOG.error("统计图同环比计算出错：", e);
        }
        return oldVal;
    }

    /**
     * 同环比差值处理（统计表计算出同（环）比的时间，统计图计算es相差的桶数）
     *
     * @param chartType
     * @param dateFieldAttrPojo
     * @param advancedComputing
     * @param timestamp
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/6/8 16:11
     * @version 1.0
     */
    public Long getYearChainDiff(Integer chartType, FieldAttrPojo dateFieldAttrPojo, JSONArray advancedComputing, Long timestamp) {
        String secondType = advancedComputing.getString(1);
        Long value = null;
        IntervalTypeEnum intervalTypeEnum = IntervalTypeEnum.getByFormatStr(dateFieldAttrPojo.getDateGroupType());
        // 获取差值
        if (Objects.equals(AdvancedComputingSecondEnum.getYearOrChain(secondType), YearChainEnum.YEAR_ON_YEAR.getValue())) {
            // 同比
            value = getYearOnYear(chartType, intervalTypeEnum, timestamp);
        } else if (Objects.equals(AdvancedComputingSecondEnum.getYearOrChain(secondType), YearChainEnum.CHAIN_ON_CHAIN.getValue())) {
            // 环比
            value = getChainOnChain(chartType, intervalTypeEnum, timestamp);
        }
        return value;
    }


    /**
     * 同比
     *
     * @param chartType
     * @param intervalTypeEnum
     * @param timestamp
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/6/8 16:12
     * @version 1.0
     */
    private Long getYearOnYear(Integer chartType, IntervalTypeEnum intervalTypeEnum, Long timestamp) {
        Long value = null;
        if (Objects.equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode(), chartType)) {
            Calendar oldDate = Calendar.getInstance();
            oldDate.setTime(new Date(timestamp));
            oldDate.add(Calendar.YEAR, -1);
            value = oldDate.getTimeInMillis();
        } else {
            switch (intervalTypeEnum) {
                case YEAR:
                    value = LagEnum.YEAR_YEAR.getValue().longValue();
                    break;
                case YEAR_QUARTER:
                    value = LagEnum.YEAR_QUARTER.getValue().longValue();
                    break;
                case YEAR_MONTH:
                    value = LagEnum.YEAR_MONTH.getValue().longValue();
                    break;
                case YEAR_MONTH_DAY:
                    // 处理366天的问题
                    value = LagEnum.getYearMonthDay(timestamp);
                    break;
                default:
                    break;
            }
        }
        return value;
    }

    /**
     * 环比
     *
     * @param chartType
     * @param intervalTypeEnum
     * @param timestamp
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/6/8 16:12
     * @version 1.0
     * @return
     */
    private Long getChainOnChain(Integer chartType, IntervalTypeEnum intervalTypeEnum, Long timestamp) {
        Long value = null;
        Calendar oldDate = Calendar.getInstance();
        oldDate.setTime(new Date(timestamp));
        if (Objects.equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode(), chartType)) {
            switch (intervalTypeEnum) {
                case YEAR:
                    oldDate.add(Calendar.YEAR, -1);
                    break;
                case YEAR_QUARTER:
                    oldDate.add(Calendar.MONTH, -3);
                    break;
                case YEAR_MONTH:
                    oldDate.add(Calendar.MONTH, -1);
                    break;
                case YEAR_MONTH_DAY:
                    oldDate.add(Calendar.DATE, -1);
                    break;
                default:
                    break;
            }
            value = oldDate.getTimeInMillis();
        } else {
            switch (intervalTypeEnum) {
                case YEAR:
                    value = LagEnum.CHAIN_YEAR.getValue().longValue();
                    break;
                case YEAR_QUARTER:
                    value = LagEnum.CHAIN_QUARTER.getValue().longValue();
                    break;
                case YEAR_MONTH:
                    value = LagEnum.CHAIN_MONTH.getValue().longValue();
                    break;
                case YEAR_MONTH_DAY:
                    value = LagEnum.CHAIN_MONTH_DAY.getValue().longValue();
                    break;
                default:
                    break;
            }
        }
        return value;
    }

    /**
     * 同环比计算
     * @param fieldAttrPojo 统计值pojo
     * @param oldValueStr 同（环）期值
     * @param nowValueStr 当期值
     * @return java.lang.String 同环比结果值
     * @author xinpeng.jiang
     * @date 2021/6/10 9:48
     * @version 1.0
     */
    public String getYearChainValue(FieldAttrPojo fieldAttrPojo, String oldValueStr, String nowValueStr) {
        JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
        Integer accuracy = fieldAttrPojo.getAccuracy();
        if (AdvancedComputingFirstEnum.noneYearChain(advancedComputing)) {
            return nowValueStr;
        }
        if ("".equals(nowValueStr) || Objects.isNull(nowValueStr)) {
            return StringConstant.ZERO;
        }
        if ("".equals(oldValueStr) || Objects.isNull(oldValueStr)) {
            oldValueStr = StringConstant.ZERO;
        }
        BigDecimal oldValue = new BigDecimal(oldValueStr);
        BigDecimal nowValue = new BigDecimal(nowValueStr);
        BigDecimal diffValue = nowValue.subtract(oldValue);
        // 比值
        if (Objects.equals(AdvancedComputingSecondEnum.getValueOrRate(advancedComputing.getString(1)), ValueRateEnum.VALUE.getValue())) {
            return diffValue.toString();
        }
        // 比率
        // 同（环）期值为0，显示0
        if (BigDecimal.ZERO.compareTo(oldValue) == 0) {
            return StringConstant.ZERO;
        }
        // 如果当期值为0
        if (BigDecimal.ZERO.compareTo(nowValue) == 0) {
            // 同（环）期值为负，比率为-1
            if (BigDecimal.ZERO.compareTo(oldValue) < 0) {
                return StringConstant.NEGATIVE_NUMBER;
            }
            // 同（环）期值为正，比率为1
            if (BigDecimal.ZERO.compareTo(oldValue) > 0) {
                return StringConstant.POSITIVE_NUMBER;
            }
        }
        // 百分比渲染精度增加
        if (Objects.equals(fieldAttrPojo.getPercentUsed(), 1)) {
            accuracy += 2;
        }
        return diffValue.divide(oldValue.abs(), accuracy, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 对汇总数据格式化
     *
     * @param summaryAttrMap 汇总字段映射
     * @param total          汇总数据
     */
    public void formatAggData(Map<String, FieldAttrPojo> summaryAttrMap, Map<String, Object> total) {
        Iterator<Map.Entry<String, Object>> iterator = total.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> totalEntry = iterator.next();
            String value = totalEntry.getValue().toString();
            if (StringUtil.isEmpty(value) || Objects.equals(value, StringConstant.SHORT_BARS)) {
                continue;
            }
            String key = totalEntry.getKey();
            FieldAttrPojo fieldAttrPojo = summaryAttrMap.get(key);
            //汇总方式
            String aggType = "";
            // 小数精度
            Integer accuracy = 2;
            // 是否使用百分比
            Integer percentUsed = 0;
            // 是否使用千分符
            Integer groupingUsed = 0;
            // 数值格式
            Integer numFormat = NumFormatEnum.DEFAULT.getCode();
            if (fieldAttrPojo != null) {
                accuracy = fieldAttrPojo.getAccuracy();
                accuracy = accuracy == null ? 0 : accuracy;
                if (Objects.nonNull(fieldAttrPojo.getPercentUsed())) {
                    percentUsed = fieldAttrPojo.getPercentUsed();
                }
                groupingUsed = fieldAttrPojo.getGroupingUsed() == null ? fieldAttrPojo.getAmountFlag() : fieldAttrPojo.getGroupingUsed();
                numFormat = fieldAttrPojo.getNumFormat();
            }
            NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
            String unit = numFormatEnum.getNoYuanUnit();
            String newVal = String.valueOf(ChartResultUtil.formatVal4Num(new BigDecimal(value), numFormatEnum));
            String resultDecimal = attrDecimalPrecisionHelper.getNumberFormat(newVal, accuracy, groupingUsed, percentUsed);
            if (StringUtil.isNotEmpty(unit)) {
                resultDecimal += unit;
            }
            total.put(key, resultDecimal);
        }
    }

    /**
     * 解析关联数据
     * @param parseMap
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/11/12 16:52
     * @version 1.0
     */
    public Map<String, String> parseLinkBusinessMap(Map<String, String> parseMap) {
        Map<String, String> parseLinkMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Iterator<Map.Entry<String, String>> it = parseMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            String key = entry.getKey();
            String value = entry.getValue();
            if (Objects.nonNull(key)) {
                if (key.startsWith(ChartConstant.LEFT_PARENTHESES)) {
                    key = key.substring(1);
                }
                if (key.endsWith(ChartConstant.RIGHT_PARENTHESES)) {
                    key = key.substring(0, key.length() - 1);
                }
            }
            if (Objects.nonNull(value)) {
                if (value.startsWith(ChartConstant.LEFT_PARENTHESES)) {
                    value = value.substring(1);
                }
                if (value.endsWith(ChartConstant.RIGHT_PARENTHESES)) {
                    value = value.substring(0, value.length() - 1);
                }
            }

            if (Objects.nonNull(key)) {
                String[] keys = key.split(BasicConstant.COMMA);
                String[] values = value.split(BasicConstant.COMMA);
                if (Objects.equals(keys.length, values.length) && keys.length > 1) {
                    for (int i = 0; i < keys.length; i++) {
                        parseLinkMap.put(keys[i].trim(), values[i].trim());
                    }
                } else if (Objects.equals(keys.length, values.length) && Objects.equals(keys.length, BasicConstant.ONE)) {
                    parseLinkMap.put(key.trim(), value.trim());
                }
            }
        }
        return parseLinkMap;
    }

    /**
     * 判断当前这个预警数据之前是否被触发过，是否需要覆盖。
     * @param triggerCondition 触发条件
     * @param dataValue 当前图表循环到的数据
     * @param distinctMap 存储预警的相关数据
     * @param index 循环的index
     * @return
     */
    public boolean isCover(JSONArray triggerCondition, String dataValue, Map < String, Object > distinctMap, int index){
        if (!(Objects.nonNull(triggerCondition) && Objects.nonNull(dataValue) && !dataValue.isEmpty())) {
            return false;
        }
        // 1.看看这个值之前是否预警过，是要替代还是跳过
        List<DwTriggerConditionPojo> triggerConditionList = triggerCondition.toJavaList(DwTriggerConditionPojo.class);
        if (CollectionUtils.isEmpty(triggerConditionList)) {
            return false;
        }
        // 只有一个预警条件
        DwTriggerConditionPojo pojo = triggerConditionList.get(0);
        BigDecimal dataNumberValue = new BigDecimal(dataValue.replaceAll(",","").replaceAll("%",""));
        BigDecimal minDistant;
        Boolean coverFlag = false;
        String distanceKey = index + "&" + "distance";
        String valueKey = index + "&" + "distance";
        for (BigDecimal value : pojo.getValue()) {
            if (distinctMap.containsKey(distanceKey)) {
                minDistant = (value.subtract(dataNumberValue)).abs();
                if (minDistant.compareTo((BigDecimal) distinctMap.get(distanceKey)) < 0) {
                    distinctMap.put(valueKey, dataNumberValue);
                    distinctMap.put(distanceKey, minDistant);
                    coverFlag = true;
                }
                continue;
            } else {
                minDistant = (value.subtract(dataNumberValue)).abs();
                distinctMap.put(valueKey, dataNumberValue);
                distinctMap.put(distanceKey, minDistant);
                coverFlag = true;
            }
        }
        return coverFlag;
    }

    /**
     * chartValue和chartValueSecond转换成jsonObject
     * @param chartEntity
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/11/16 14:38
     * @version 1.0
     */
    public void transformObj(ChartEntity chartEntity) {
        JSONArray chartValue = chartEntity.getChartValue();
        if (CollectionUtils.isNotEmpty(chartValue)) {
            JSONArray newValArr = new JSONArray(chartValue.size());
            for (Object obj : chartValue) {
                JSONObject valObj = JSON.parseObject(JSON.toJSONString(obj));
                newValArr.add(valObj);
            }
            chartEntity.setChartValue(newValArr);
        }
        // 双轴图
        JSONArray chartValueSecond = chartEntity.getChartValueSecond();
        if (CollectionUtils.isNotEmpty(chartValueSecond)) {
            JSONArray newValArr = new JSONArray(chartValueSecond.size());
            for (Object obj : chartValueSecond) {
                JSONObject valObj = JSON.parseObject(JSON.toJSONString(obj));
                newValArr.add(valObj);
            }
            chartEntity.setChartValueSecond(newValArr);
        }
    }

    /**
     * 将副指标里面的时间维度及解析成筛选条件
     * @param timeDimension
     * @param secondTargetKey
     * @return
     */
    public List<Long> getSecondTargetFilter(String timeDimension,JSONArray advancedComputing,List<String> secondTargetKey, NormalTypeEnum normalTypeEnum){
        List<Long> valueList = new ArrayList<>();
        IntervalTypeEnum intervalTypeEnum = IntervalTypeEnum.getByFormatStr(timeDimension);
        Calendar calendar = Calendar.getInstance();
        Calendar calendarStart = Calendar.getInstance();
        Calendar calendarEnd = Calendar.getInstance();
        Calendar stCalendarStart = Calendar.getInstance();
        calendarStart.set(Calendar.HOUR_OF_DAY,0);
        calendarStart.set(Calendar.MINUTE,0);
        calendarStart.set(Calendar.SECOND,0);
        calendarStart.set(Calendar.MILLISECOND,0);
        calendarEnd.set(Calendar.HOUR_OF_DAY,0);
        calendarEnd.set(Calendar.MINUTE,0);
        calendarEnd.set(Calendar.SECOND,0);
        calendarEnd.set(Calendar.MILLISECOND,0);
        stCalendarStart.set(Calendar.HOUR_OF_DAY,0);
        stCalendarStart.set(Calendar.MINUTE,0);
        stCalendarStart.set(Calendar.SECOND,0);
        stCalendarStart.set(Calendar.MILLISECOND,0);
        // 是否同比
        boolean isYear = false;
        boolean isYearChain = isYearChain4Subtitle(advancedComputing);
        if (isYearChain){
            isYear = Objects.equals(AdvancedComputingSecondEnum.getYearOrChain(advancedComputing.getString(1)),1);
        }
        boolean flag = !Objects.equals(NormalTypeEnum.UNKNOWN, normalTypeEnum) && !Objects.isNull(normalTypeEnum);
        switch (intervalTypeEnum){
            case YEAR:
                // 去年到今年
                calendarStart.set(Calendar.YEAR,calendar.get(Calendar.YEAR)-1);
                calendarStart.set(Calendar.DAY_OF_YEAR,calendarStart.getActualMinimum(Calendar.DAY_OF_YEAR));
                calendarEnd.set(Calendar.YEAR,calendar.get(Calendar.YEAR)+1);
                calendarEnd.set(Calendar.DAY_OF_YEAR,calendarStart.getActualMinimum(Calendar.DAY_OF_YEAR));
                stCalendarStart.set(Calendar.DAY_OF_YEAR,calendarStart.getActualMinimum(Calendar.DAY_OF_YEAR));
                if (flag) {
                    if (Objects.equals(NormalTypeEnum.LAST_YEAR, normalTypeEnum)) {
                        calendarStart.add(Calendar.YEAR, -1);
                        calendarEnd.add(Calendar.YEAR, -1);
                        stCalendarStart.add(Calendar.YEAR, -1);
                    } else if (Objects.equals(NormalTypeEnum.THIS_YEAR, normalTypeEnum)) {
                        calendarStart.add(Calendar.YEAR, 0);
                        calendarEnd.add(Calendar.YEAR, 0);
                    } else {
                        calendarStart.add(Calendar.YEAR, 1);
                        calendarEnd.add(Calendar.YEAR, 1);
                        stCalendarStart.add(Calendar.YEAR, 1);
                    }
                }
                break;
            case YEAR_QUARTER:
                stCalendarStart.setTimeInMillis(DateTimeUtil.getFirstDateOfSeason(calendar.getTimeInMillis()/1000)*1000);
                if (isYear){
                    calendarEnd.setTimeInMillis(DateTimeUtil.getLastDateOfSeason(calendar.getTimeInMillis()/1000)*1000);
                    calendar.add(Calendar.YEAR,-1);
                    calendarStart.setTimeInMillis(DateTimeUtil.getFirstDateOfSeason(calendar.getTimeInMillis()/1000)*1000);
                }else {
                    calendarEnd.setTimeInMillis(DateTimeUtil.getLastDateOfSeason(calendar.getTimeInMillis()/1000)*1000);
                    calendarStart.setTimeInMillis(DateTimeUtil.getFirstDateOfLastSeason(calendar.getTimeInMillis()/1000)*1000);
                }
                if (flag) {
                    if (Objects.equals(NormalTypeEnum.LAST_QUARTER, normalTypeEnum)) {
                        calendarStart.setTimeInMillis(DateTimeUtil.getFirstDateOfLastSeason(calendarStart.getTimeInMillis()/1000)*1000);
                        stCalendarStart.setTimeInMillis(DateTimeUtil.getFirstDateOfLastSeason(stCalendarStart.getTimeInMillis()/1000)*1000);
                    }
                    if (Objects.equals(NormalTypeEnum.NEXT_QUARTER, normalTypeEnum)){
                        calendarStart.setTimeInMillis(DateTimeUtil.getFirstDateOfNextSeason(calendarStart.getTimeInMillis()/1000)*1000);
                        stCalendarStart.setTimeInMillis(DateTimeUtil.getFirstDateOfNextSeason(stCalendarStart.getTimeInMillis()/1000)*1000);
                    }
                }
                break;
            case YEAR_MONTH:
                calendarStart.set(Calendar.DATE, 1);
                calendarEnd.set(Calendar.DATE, 1);
                stCalendarStart.set(Calendar.DATE, 1);
                if (isYear){
                    calendarStart.add(Calendar.YEAR,-1);
                    calendarStart.set(Calendar.DATE, 1);
                    calendarEnd.set(Calendar.DATE, 1);
                    calendarEnd.add(Calendar.MONTH,1);
                }else {
                    calendarStart.add(Calendar.MONTH,-1);
                    calendarEnd.add(Calendar.MONTH,1);
                }
                if (flag) {
                    if (Objects.equals(NormalTypeEnum.LAST_MONTH, normalTypeEnum)) {
                        calendarStart.add(Calendar.MONTH, -1);
                        calendarEnd.add(Calendar.MONTH, -1);
                        stCalendarStart.add(Calendar.MONTH, -1);
                    } else if (Objects.equals(NormalTypeEnum.THIS_MONTH, normalTypeEnum)) {
                        calendarStart.add(Calendar.MONTH, 0);
                        calendarEnd.add(Calendar.MONTH, 0);
                    } else {
                        calendarStart.add(Calendar.MONTH, 1);
                        calendarEnd.add(Calendar.MONTH, 1);
                        stCalendarStart.add(Calendar.MONTH, 1);
                    }
                }
                break;
            case YEAR_WEEK:
                calendarStart.set(Calendar.DAY_OF_WEEK,2);
                calendarStart.add(Calendar.WEEK_OF_MONTH,-1);
                calendarEnd.set(Calendar.DAY_OF_WEEK,2);
                calendarEnd.add(Calendar.WEEK_OF_MONTH,1);
                stCalendarStart.set(Calendar.DAY_OF_WEEK,2);
                if (flag) {
                    if (Objects.equals(NormalTypeEnum.LAST_WEEK, normalTypeEnum)) {
                        calendarStart.add(Calendar.WEEK_OF_MONTH, -1);
                        calendarEnd.add(Calendar.WEEK_OF_MONTH, -1);
                        stCalendarStart.add(Calendar.WEEK_OF_MONTH, -1);
                    } else if (Objects.equals(NormalTypeEnum.THIS_WEEK, normalTypeEnum)) {
                        calendarStart.add(Calendar.WEEK_OF_MONTH, 0);
                        calendarEnd.add(Calendar.WEEK_OF_MONTH, 0);
                    } else {
                        calendarStart.add(Calendar.WEEK_OF_MONTH, 1);
                        calendarEnd.add(Calendar.WEEK_OF_MONTH, 1);
                        stCalendarStart.add(Calendar.WEEK_OF_MONTH, 1);
                    }
                }
                break;
            case YEAR_MONTH_DAY:
                calendarStart.add(Calendar.DAY_OF_MONTH,-1);
                calendarEnd.add(Calendar.DAY_OF_MONTH,1);
                if (flag) {
                    if (Objects.equals(NormalTypeEnum.YESTERDAY, normalTypeEnum)) {
                        calendarStart.add(Calendar.DAY_OF_MONTH, -1);
                        calendarEnd.add(Calendar.DAY_OF_MONTH, -1);
                        stCalendarStart.add(Calendar.DAY_OF_MONTH, -1);
                    } else if (Objects.equals(NormalTypeEnum.TODAY, normalTypeEnum)) {
                        calendarStart.add(Calendar.DAY_OF_MONTH, 0);
                        calendarEnd.add(Calendar.DAY_OF_MONTH, 0);
                    } else {
                        calendarStart.add(Calendar.DAY_OF_MONTH, 1);
                        calendarEnd.add(Calendar.DAY_OF_MONTH, 1);
                        stCalendarStart.add(Calendar.DAY_OF_MONTH, 1);
                    }
                }
                break;
            default:
                break;
        }
        valueList.add(calendarStart.getTimeInMillis()/1000);
        valueList.add(calendarEnd.getTimeInMillis()/1000);
        secondTargetKey.add(String.valueOf(calendarStart.getTimeInMillis()));
        secondTargetKey.add(String.valueOf(stCalendarStart.getTimeInMillis()));
        return valueList;
    }

    /**
     * 字段 数字数据格式化
     *
     */
    public String fieldAttrPojoFormat(FieldAttrPojo fieldAttrPojo, String num) {
        if (Objects.isNull(fieldAttrPojo)) {
            return num;
        }
        Integer accuracy = fieldAttrPojo.getAccuracy();
        accuracy = accuracy == null ? 0 : accuracy;
        Integer percentUsed = fieldAttrPojo.getPercentUsed();
        Integer groupingUsed = fieldAttrPojo.getGroupingUsed() == null ? fieldAttrPojo.getAmountFlag() : fieldAttrPojo.getGroupingUsed();
        String result = attrDecimalPrecisionHelper.getNumberFormat(num, accuracy, groupingUsed, percentUsed);
        return result;
    }

    /**
     * 逆向 将格式化的数据转成之前的值去除%和千分号、数值格式
     *
     */
    public String reverseFieldAttrPojoFormat(FieldAttrPojo fieldAttrPojo, String num) {
        if (Objects.isNull(fieldAttrPojo)) {
            return num;
        }
        Integer accuracy = fieldAttrPojo.getAccuracy();
        accuracy = accuracy == null ? 0 : accuracy;
        Integer percentUsed = fieldAttrPojo.getPercentUsed();
        Integer groupingUsed = fieldAttrPojo.getGroupingUsed() == null ? fieldAttrPojo.getAmountFlag() : fieldAttrPojo.getGroupingUsed();
        // 千分符
        if (Objects.equals(groupingUsed,1)){
            num = num.replaceAll(StringConstant.COMMA,"");
        }
        // 数值格式，先替换掉单位
        Integer numFormat = fieldAttrPojo.getNumFormat();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        num = num.replaceAll(numFormatEnum.getNoYuanUnit(),"");
        // 百分比
        if (Objects.equals(percentUsed,1)){
            num = num.replaceAll(StringConstant.PERCENT,"");
            num = String.valueOf(new BigDecimal(num).divide(new BigDecimal("100"),accuracy));
        }
        // 数值格式，数字还原
        num = String.valueOf(ChartResultUtil.formatVal4NumRevert(new BigDecimal(num), numFormatEnum));
        return num;
    }

    /**
     * 副指标同环比判断
     * @param advancedComputing 高级条件
     * @return
     */
    public boolean isYearChain4Subtitle(JSONArray advancedComputing) {
        return advancedComputing != null && Objects.equals(advancedComputing.getString(0), AdvancedComputingFirstEnum.YEAR_CHAIN.getAlias()) && advancedComputing.size() > 1;
    }

    /**
     * 不显示离职人员
     * @param chartEntity
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/8/26 10:44
     * @version 1.0
     */
    public void handleLeaveNoShow(ChartEntity chartEntity) {
        String corpid = chartEntity.getCorpid();
        JSONArray filterArr = chartEntity.getFilter();
        if (CollectionUtils.isEmpty(filterArr)) {
            return;
        }
        // 离职员工
        List<String> leaveUserIdList = new ArrayList<>();
        boolean isNeedSelect = true;
        for (int i = 0, filterArrSize = filterArr.size(); i < filterArrSize; i++) {
            Object filter = filterArr.get(i);
            JSONObject filterObj = filter instanceof Map ? JSON.parseObject(JSON.toJSONString(filter)) : new JSONObject();
            if (Objects.equals(filterObj.getString(StringConstant.LEAVE_MARKS), LeaveMarksEnum.NO_SHOW.getCode())) {
                ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(filterObj.getString(StringConstant.SYMBOL));
                if (Objects.isNull(conditionEnum)) {
                    continue;
                }
                JSONArray selectUserArr = filterObj.getJSONArray(StringConstant.VALUE);
                // 获取选中userId
                Set<String> selectUserIdSet = new HashSet<>();
                if (CollectionUtils.isNotEmpty(selectUserArr)) {
                    for (Object obj : selectUserArr) {
                        String userId = "";
                        if (obj instanceof String) {
                            userId = String.valueOf(obj);
                        } else if (obj instanceof JSONObject) {
                            JSONObject jsonObject = (JSONObject) obj;
                            userId = jsonObject.getString(ParameterConstant.USER_ID);
                        }
                        if (StringUtil.isNotEmpty(userId)) {
                            selectUserIdSet.add(userId);
                        }
                    }
                    // 后面重新赋值，保持集合内结构一致
                    selectUserArr.clear();
                } else {
                    // 除以下情况，其余情况需要查离职人员
                    if (Objects.equals(conditionEnum, ConditionEnum.EQUAL) || Objects.equals(conditionEnum, ConditionEnum.IN)) {
                        continue;
                    }
                    selectUserArr = new JSONArray();
                }
                // 一次性获取离职人员
                if (isNeedSelect) {
                    Map<String, Object> params = new HashMap<>(2);
                    params.put(ParameterConstant.CORPID, corpid);
                    params.put(ParameterConstant.NEG_DEL, DelEnum.NORMAL.getDel());
                    leaveUserIdList = userModel.getUserIds(params);
                    isNeedSelect = false;
                    if (CollectionUtils.isEmpty(leaveUserIdList)) {
                        break;
                    }
                }
                // 剔除离职员工
                switch (conditionEnum) {
                    case EQUAL:
                    case IN:
                    case INCLUDE:
                        leaveUserIdList.forEach(selectUserIdSet::remove);
                        selectUserArr.addAll(selectUserIdSet);
                        break;
                    case NOEQUAL:
                    case NOIN:
                    case NOEMPTY:
                        selectUserArr.addAll(selectUserIdSet);
                        selectUserArr.addAll(leaveUserIdList);
                        filterObj.put(StringConstant.SYMBOL, ConditionEnum.NOIN.getSymbol());
                        break;
                    default:
                        break;
                }
                // 移除离职人员后为空默认塞个-1，免得后面has_child被过滤掉
                if (CollectionUtils.isEmpty(selectUserArr)) {
                    selectUserArr.add("-1");
                }
                filterObj.put(StringConstant.VALUE, selectUserArr);
                filterArr.set(i, filterObj);
            }
            chartEntity.setFilter(filterArr);
        }
    }

    /**
     * 处理常用筛选
     * @param conditionObj
     * @return java.util.Map<java.lang.String, java.lang.Long>
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/10/14 16:39
     * @version 1.0
     */
    public Map<String, Long> handleNormalFilter(JSONObject conditionObj) {
        Map<String, Long> result = new HashMap<>(2);
        Long startTimestamp = null;
        Long endTimestamp = null;
        Long startOfDay = DateTimeUtil.getStartOfDay(DateUtil.getNow());
        Long endOfDay = DateTimeUtil.getEndOfDay(DateUtil.getNow());
        Integer normalType = conditionObj.getInteger("normalType");
        NormalTypeEnum normalTypeEnum = NormalTypeEnum.getByCode(normalType);
        switch (normalTypeEnum) {
            case YESTERDAY:
                startTimestamp = DateTimeUtil.getTimestampByCalendarType(startOfDay, -1, Calendar.DATE);
                endTimestamp = DateTimeUtil.getTimestampByCalendarType(endOfDay, -1, Calendar.DATE);
                break;
            case TODAY:
                startTimestamp = startOfDay;
                endTimestamp = endOfDay;
                break;
            case TOMORROW:
                startTimestamp = DateTimeUtil.getTimestampByCalendarType(startOfDay, 1, Calendar.DATE);
                endTimestamp = DateTimeUtil.getTimestampByCalendarType(endOfDay, 1, Calendar.DATE);
                break;
            case AFTER_TODAY:
                startTimestamp = DateTimeUtil.getTimestampByCalendarType(endOfDay, 1, Calendar.DATE);
                break;
            case LAST_WEEK:
                startTimestamp = DateTimeUtil.getLastWeekMondayInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getWeekMorningInSomeday(endOfDay);
                break;
            case THIS_WEEK:
                startTimestamp = DateTimeUtil.getWeekMorningInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getWeekSundayInSomeday(endOfDay);
                break;
            case NEXT_WEEK:
                startTimestamp = DateTimeUtil.getWeekSundayInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getNextWeekSundayInSomeday(endOfDay);
                break;
            case LAST_MONTH:
                startTimestamp = DateTimeUtil.getFirstDateOfLastMonth(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfLastMonth(endOfDay);
                break;
            case THIS_MONTH:
                startTimestamp = DateTimeUtil.getFirstDateOfThisMonth();
                endTimestamp = DateTimeUtil.getLastDateOfThisMonth();
                break;
            case NEXT_MONTH:
                startTimestamp = DateTimeUtil.getLastDateOfMonthInSomeday(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfNextMonthInSomeday(endOfDay);
                break;
            case LAST_QUARTER:
                startTimestamp = DateTimeUtil.getFirstDateOfLastSeason(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfLastSeason(endOfDay);
                break;
            case THIS_QUARTER:
                startTimestamp = DateTimeUtil.getFirstDateOfSeason(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfSeason(endOfDay);
                break;
            case NEXT_QUARTER:
                startTimestamp = DateTimeUtil.getFirstDateOfNextSeason(startOfDay);
                endTimestamp = DateTimeUtil.getLastDateOfNextSeason(endOfDay);
                break;
            case LAST_YEAR:
                startTimestamp = DateTimeUtil.getFirstDateOfPreviousYear();
                endTimestamp = DateTimeUtil.getFirstDateOfYear();
                break;
            case THIS_YEAR:
                startTimestamp = DateTimeUtil.getFirstDateOfYear();
                endTimestamp = DateTimeUtil.getLastDateOfYear();
                break;
            case NEXT_YEAR:
                startTimestamp = DateTimeUtil.getLastDateOfYear();
                endTimestamp = DateTimeUtil.getLastDateOfNextYear();
                break;
            default:
                break;
        }
        result.put("startTimestamp", startTimestamp);
        result.put("endTimestamp", endTimestamp);
        return result;
    }

    /**
     * 处理筛选动态值
     * @param DateType 日期类型
     * @param DateWay 时间类型
     * @param interval 间隔
     * @param isStart 开始or结束时间
     * @author xinpeng.jiang
     * @date 2021/10/13 11:29
     * @version 1.0
     */
    public Long handleDynamicDate(Integer DateType, Integer DateWay, Integer interval, boolean isStart) {
        long date;
        // 取一天的开始或结束时间
        if (isStart) {
            date = DateTimeUtil.getStartOfDay(DateUtil.getNow());
        } else {
            date = DateTimeUtil.getEndOfDay(DateUtil.getNow());
        }

        if (Objects.equals(DateWay, DateWayEnum.BEFORE.getCode())) {
            // 过去的间隔要取反
            interval = -interval;
            return getTimestampByDateType(DateType, interval, date);
        }
        if (Objects.equals(DateWay, DateWayEnum.NOW.getCode())) {
            return date;
        }
        if (Objects.equals(DateWay, DateWayEnum.FEATURE.getCode())) {
            return getTimestampByDateType(DateType, interval, date);
        }

        return null;
    }

    /**
     * 根据日期类型获取差值时间戳
     * @param DateType 日期类型
     * @param interval 间隔
     * @param date 秒级时间戳
     * @return java.lang.Integer
     * @author xinpeng.jiang
     * @date 2021/10/13 13:45
     * @version 1.0
     */
    private static Long getTimestampByDateType(Integer DateType, Integer interval, long date) {
        Long timestamp = null;
        DateTypeEnum dateTypeEnum = DateTypeEnum.getByCode(DateType);
        switch (dateTypeEnum) {
            case DAY:
                timestamp = DateTimeUtil.getTimestampByCalendarType(date, interval, Calendar.DATE);
                break;
            case WEEK:
                interval = interval * 7;
                timestamp = DateTimeUtil.getTimestampByCalendarType(date, interval, Calendar.DATE);
                break;
            case MONTH:
                timestamp = DateTimeUtil.getTimestampByCalendarType(date, interval, Calendar.MONTH);
                break;
            default:
                break;
        }
        return timestamp;
    }

    /**
     * 地图
     * @param chartEntity
     * @param conditionJson
     */
    public void parseMap(ChartEntity chartEntity,JSONArray conditionJson){
        if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.MAP_CUSTOM.getCode())){
            JSONObject map = chartEntity.getMap();
            if (null == map){
                JSONObject explains = chartEntity.getExplains();
                if(explains != null ) {
                    map = JSON.parseObject(JSON.toJSONString(explains.get(StringConstant.MAP)));
                    if (null == map){
                        return;
                    }
                }else {
                    return;
                }
            }
            if (null == map){
                return;
            }
            JSONArray chartClassifyArray = chartEntity.getChartClassify();
            JSONArray range = map.getJSONArray(StringConstant.RANGE);
            if(CollectionsUtil.isEmpty(chartClassifyArray) || CollectionsUtil.isEmpty(range)){
                return;
            }
            JSONObject chartClassify;
            chartClassify = chartClassifyArray.getJSONObject(0);
            FieldAttrPojo chartClassifyAttr = JSONObject.parseObject(chartClassify.toJSONString(), FieldAttrPojo.class);
            FieldAttrPojo provinceFieldAttr = (FieldAttrPojo) CloneUtil.deepClone(chartClassifyAttr);
            FieldAttrPojo cityFieldAttr = (FieldAttrPojo) CloneUtil.deepClone(chartClassifyAttr);
            FieldAttrPojo districtFieldAttr = (FieldAttrPojo) CloneUtil.deepClone(chartClassifyAttr);

            String alias = range.getString(0);
            AreaTypeEnum areaTypeEnum = AreaTypeEnum.getByAlias(alias);
            if (AreaTypeEnum.isAddRange(alias)){
                JSONObject conditionObject = (JSONObject) CloneUtil.deepClone(chartClassify);
                range.remove(0);
                conditionObject.put("value",range);
                conditionObject.put("symbol",ConditionEnum.EQUAL.getSymbol());
                conditionJson.add(conditionObject);
                // 台湾省特殊处理
                if (CollectionsUtil.isNotEmpty(range) && Objects.equals(range.get(0),StringConstant.TAIWAN_PROVINCE)){
                    areaTypeEnum = AreaTypeEnum.CHINA;
                }
            }

            switch (areaTypeEnum){
                case PROVINCE:
                    cityFieldAttr.setAttr(chartClassifyAttr.getAttr() + StringConstant.POINT + AreaTypeEnum.CITY.getAlias());
                    chartClassifyArray = new JSONArray();
                    chartClassifyArray.add(JSONObject.toJSON(cityFieldAttr));
                    chartEntity.setChartClassify(chartClassifyArray);
                    break;
                case CITY:
                    districtFieldAttr.setAttr(chartClassifyAttr.getAttr() + StringConstant.POINT + AreaTypeEnum.DISTRICT.getAlias());
                    chartClassifyArray = new JSONArray();
                    chartClassifyArray.add(JSONObject.toJSON(districtFieldAttr));
                    chartEntity.setChartClassify(chartClassifyArray);
                    break;
                default:
                    provinceFieldAttr.setAttr(chartClassifyAttr.getAttr() + StringConstant.POINT + AreaTypeEnum.PROVINCE.getAlias());
                    chartClassifyArray = new JSONArray();
                    chartClassifyArray.add(JSONObject.toJSON(provinceFieldAttr));
                    chartEntity.setChartClassify(chartClassifyArray);
                    break;
            }

        }
    }

    /**
     * 获取各个业务的子表单枚举
     *
     * @param saasMark
     * @param businessType
     * @return
     * @throws XbbException
     */
    public IndexTypeEnum getSubFormIndexTypeEnum(Integer saasMark, Integer businessType, Long formId, String corpId) throws XbbException {
        IndexTypeEnum indexTypeEnum;
        if (Objects.equals(SaasMarkEnum.PAAS.getCode(), saasMark)) {
            indexTypeEnum = IndexTypeEnum.IDX_SUB_FORM_DATA;
        } else {
            if (businessType == null || businessType.equals(0)) {
                //查询表单的具体信息
                PaasFormEntity paasFormEntity = paasFormModel.getByFormId(formId, corpId);
                if(paasFormEntity == null){
                    LOG.error("businessType为空");
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                }
                if(paasFormEntity.getBusinessType() == 0){
                    return IndexTypeEnum.IDX_SUB_FORM_DATA;
                }
                businessType = paasFormEntity.getBusinessType();
            }
            indexTypeEnum = indexTypeModel.getSubIndexType(corpId, businessType, saasMark);
        }
        return indexTypeEnum;
    }

    /**
     * 通过数据库查询表单数据对应的子表单数据
     *
     * @param corpid 公司主键id
     * @param dataId 表单数据主键id
     * @param indexTypeEnum 各业务对应的枚举
     * @param attr 子表单字段
     * @param pageHelper 分页实体
     * @return 子表单数据数组
     * @author zyy
     * @date 2022/6/21
     * @version v1.0
     */
    public List<? extends PaasFormSubDataEntity> getPaasFormSubDataByIdAndAttr(String corpid, Long dataId, IndexTypeEnum indexTypeEnum, String attr, PageHelper pageHelper) throws XbbException {
        return paasFormSubDataModel.getListByIdAndAttr(dataId, corpid, indexTypeEnum, attr,pageHelper.getFrom(pageHelper.getCurrentPageNum(), pageHelper.getPageSize()),pageHelper.getPageSize());
    }

    /**
     * 通过数据库查询表单数据的总条数
     *
     * @param chartSubFormListDTO 请求入参
     * @param dataId 表单数据主键id
     * @param indexTypeEnum 各业务对应的枚举
     * @param attr 子表单字段
     * @param pageHelper 分页实体
     * @return long 数据总量
     * @author zyy
     * @date 2022/6/21
     * @version v1.0
     */
    public long getPaasFormSubDataCount(ChartSubFormListBaseDTO chartSubFormListDTO, Long dataId, IndexTypeEnum indexTypeEnum, String attr, PageHelper pageHelper) throws XbbException {
        long count;
        if(pageHelper.getCurrentPageNum() == 1){
            count = paasFormSubDataModel.getCountByIdAndAttr(dataId, chartSubFormListDTO.getCorpid(), indexTypeEnum, attr);
        }else {
            count = chartSubFormListDTO.getTotal();
        }
        return count;
    }

    /**
     * 获取系统、自定义图表
     *
     * @param statisticsTypeEnum
     * @param chartResultDTO
     * @return java.util.List<com.xbongbong.pro.domain.entity.ChartEntity>
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public List<ChartEntity> chartEntityListFactory(StatisticsTypeEnum statisticsTypeEnum, ChartResultDTO chartResultDTO) throws XbbException {
        //同时查询系统、自定义图表
        List<ChartEntity> list = ChartAnalysisFactory.getChartStrategyService(statisticsTypeEnum.getCode()).getChartList(chartResultDTO);
        if (list == null || list.size() == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }
        return list;
    }

    /**
     * 解析所有图表公共的入参
     *
     * @param chartResultDTO 入参请求实体
     * @return com.xbongbong.pro.statistic.result.pojo.ChartResultPojo
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public ChartResultPojo initChartResultPojo(ChartResultDTO chartResultDTO) throws XbbException {
        UserEntity userEntity = BeanUtil.copyProperties(chartResultDTO.getLoginUser(), UserEntity.class, false);
        //封装chartResultPojo
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4SystemFull(userEntity, chartResultDTO);
        chartResultPojo.setRowsCount(chartResultDTO.getRowsCount());
        chartResultPojo.setGlobal(chartResultDTO.getGlobal());
        //处理资金账户id
            if (chartResultDTO.getAccountId() != null) {
                List<Long> ids = fundHelp.dealWithFundAccount(chartResultDTO.getAccountId(), chartResultDTO.getCorpid());
                chartResultPojo.setAccountIdList(ids);
        }
        //处理资金账户收支情况中的类型
        if (Objects.nonNull(chartResultDTO.getType())) {
            List<Integer> types = fundHelp.dealWithFundType(chartResultDTO.getType(), chartResultDTO.getCorpid());
            chartResultPojo.setTypes(types);
        }
        return chartResultPojo;
    }

    /**
     * 根据每个图表的数据特殊处理 ChartResultPojo
     *
     * @param chartResultPojo 入参解释实体
     * @param chartEntity 图表实体
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public void putChartResultPojoOfChart(ChartResultPojo chartResultPojo, ChartEntity chartEntity){
        //把图表置入参数
        chartResultPojo.setChartEntity(chartEntity);
        if (UnitEnum.NUMBER.getName().equals(chartEntity.getUnit())){
            chartResultPojo.setValueTypeEnum(ValueTypeEnum.VALUE_INT);
        }
    }

    /**
     * 根据不同图表类型做特殊处理
     *
     * @param chartResultDTO
     * @param chartEntity
     * @param explainEntityList
     * @author zyy
     * @date 2022/10/14
     * @version v1.0
     */
    public void charTypeFilter(ChartResultDTO chartResultDTO, ChartEntity chartEntity, List<PaasFormExplainEntity> explainEntityList){
        // 自定义pk,如果穿透表头为空，则展示列表页字段
        if (Objects.equals(ChartTypeEnum.PK_CUSTOM.getCode(), chartEntity.getChartType()) && CollectionsUtil.isEmpty(chartEntity.getPenetrateAttr())) {
            List<FieldAttrEntity> fieldAttrEntityList = JSON.parseArray(explainEntityList.get(0).getExplains(), FieldAttrEntity.class);
            pkHelp.handleCustomPkThroughHead(fieldAttrEntityList);
            chartEntity.setPenetrateAttr(JSON.parseArray(JSON.toJSONString(fieldAttrEntityList)));
        }
        // 自定义地图，穿透信息
        if (Objects.equals(ChartTypeEnum.MAP_CUSTOM.getCode(),chartEntity.getChartType()) && null != chartResultDTO.getMap()){
            JSONObject mapObject = new JSONObject();
            mapObject.put(StringConstant.RANGE,chartResultDTO.getMap());
            chartEntity.setMap(mapObject);
        }
    }

    /**
     * 获取图表字段解释
     *
     * @param chartPenetrate 是否是穿透，true代表是图表穿透处理
     * @param list 图表实体数组
     * @param corpid 公司唯一标识
     * @param drillResultPojo 每个图表的钻取信息处理维护pojo
     * @return
     * @throws XbbException
     */
    public List<PaasFormExplainEntity> getExplainList4Chart(boolean chartPenetrate, List<ChartEntity> list, String corpid, DrillResultPojo drillResultPojo) throws XbbException {
        boolean drillFlag = drillResultPojo.getDrillFlag();
        List<PaasFormExplainEntity> explainEntityList = new ArrayList<>();
        List<Long> formIdList = new ArrayList<>();
        //工单的解释信息特殊处理（只存在查询表,单数据源的情况）
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), list.get(0).getDriverSources().getInteger(StringConstant.BUSINESS_TYPE))) {
            Long formId = list.get(0).getDriverSources().getLong(FieldAttrConstant.FORMID);
            WorkOrderExplainEntityExt workOrderExplainEntity = workOrderExplainModel.getByFormId(formId, corpid);
            if (Objects.nonNull(workOrderExplainEntity)) {
                PaasFormExplainEntity paasFormExplainEntity = new PaasFormExplainEntity(workOrderExplainEntity.getCorpid(), workOrderExplainEntity.getAppId(), workOrderExplainEntity.getMenuId(), workOrderExplainEntity.getFormId(), 1, workOrderExplainEntity.getExplains(), workOrderExplainEntity.getCreatorId(), workOrderExplainEntity.getAddTime(), workOrderExplainEntity.getUpdateTime(), workOrderExplainEntity.getDel(), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.WORK_ORDER.getCode(), DistributorMarkEnum.OTHER.getCode());
                explainEntityList.add(paasFormExplainEntity);
            }
            if (drillFlag) {
                customHelp.resetChartInfo(drillResultPojo, list.get(BasicConstant.ZERO));
            }
        } else {
            //除工单外的遍历list取formId存到集合中
            for (ChartEntity chartEntity : list) {
                if (drillFlag) {
                    if (chartPenetrate && Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())) {
                        //穿透时只替换字段，不把钻取字段左侧信息转为的filter作为图表条件，所以此处置空处理，防止后续resetChartInfo内把条件塞入chartEntity
                        drillResultPojo.getResultChartInfoMap().get(chartEntity.getId()).setFilter(null);
                    }
                    customHelp.resetChartInfo(drillResultPojo, chartEntity);
                }
                JSONArray displayAttr = chartEntity.getDisplayAttr();
                JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
                JSONArray colGroupAttr = chartEntity.getColGroupAttr();
                JSONArray chartClassify = chartEntity.getChartClassify();
                JSONArray chartSeries = chartEntity.getChartSeries();
                JSONObject driverSources = chartEntity.getDriverSources();
                if (CollectionUtils.isNotEmpty(displayAttr)) {
                    extractIdList(formIdList,displayAttr);
                }
                if (CollectionUtils.isNotEmpty(rowGroupAttr)) {
                    extractIdList(formIdList,rowGroupAttr);
                }
                if (CollectionUtils.isNotEmpty(colGroupAttr)) {
                    extractIdList(formIdList,colGroupAttr);
                }
                if (CollectionUtils.isNotEmpty(chartClassify)) {
                    extractIdList(formIdList,chartClassify);
                }
                if (CollectionUtils.isNotEmpty(chartSeries)) {
                    extractIdList(formIdList,chartSeries);
                }
                if (CollectionsUtil.isEmpty(formIdList) && !Objects.isNull(driverSources)) {
                    formIdList.add(driverSources.getLong(StringConstant.FORM_ID));
                }
            }
            //根据formId集合查询相关解释
            if (CollectionUtils.isNotEmpty(formIdList)) {
                Set<Long> temp = new HashSet<>(formIdList);
                Map<String, Object> paramMap = new HashMap<>();
                paramMap.put("formIdIn", temp);
                paramMap.put(StringConstant.CORPID, corpid);
                paramMap.put(StringConstant.DEL,0);
                explainEntityList = paasFormExplainModel.list(paramMap);
            }
        }
        if(CollectionUtils.isNotEmpty(explainEntityList)){
            for (PaasFormExplainEntity paasFormExplainEntity : explainEntityList) {
                Long formId = paasFormExplainEntity.getFormId();
                List<FieldAttrEntity> fieldAttrEntityList = JSONObject.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
                for (FieldAttrEntity fieldAttrEntity : fieldAttrEntityList) {
                    fieldAttrEntity.setFormId(formId);
                }
                paasFormExplainEntity.setExplains(JSONObject.toJSONString(fieldAttrEntityList));
            }
        }
        return explainEntityList;
    }

    /**
     * @Description 图表显示时，收集字段的formId
     * @author weiming
     * @Date  2020/5/22
     * @since
     **/
    public void extractIdList(List<Long> formIdList, JSONArray attrJsonArray) {
        for (int i = 0; i < attrJsonArray.size(); i++) {
            JSONObject jsonObject = attrJsonArray.getJSONObject(i);
            long formId = jsonObject.getLong("formId");
            formIdList.add(formId);
        }
    }

    /**
     * 处理chartList，当首页请求的时候，需要按照idIn传入的顺序返回给前端
     *
     * @param chartResultDTO 请求参数
     * @param chartMap       statisticsType_chartId---图表结果信息
     * @param chartList      图表list
     * @return java.util.List<T>
     * @author zcp
     * @date 2019/3/28 11:16
     * @version v1.0
     * @since v1.0
     */
    public <T> List<T> sortChartList(ChartResultDTO chartResultDTO, Map<String, Object> chartMap, List<T> chartList) {
        String from = chartResultDTO.getFrom();
        //当该值为“hamlet”时代表千人千面请求，需要对返回数据按照idIn的顺序封装图表
        boolean indexFlag = !StringUtil.isEmpty(from) && ResultFromEnum.getByValue(from) == ResultFromEnum.HAMLET;
        if (indexFlag) {
            List<T> sortChartList = new ArrayList<>();
            for (ChartIdPojo chartIdPojo : chartResultDTO.getChartIdIn()) {
                String key = String.format(SymbolConstant.UNDERLINE_PLACE, chartIdPojo.getStatisticsType(), chartIdPojo.getId());
                sortChartList.add((T) chartMap.get(key));
            }
            return sortChartList;
        } else {
            return chartList;
        }
    }

    public List<Long> getSubCategoryIdList(String corpid, Long categoryId) throws XbbException{
        if (Objects.isNull(categoryId)) {
            return new ArrayList<>();
        }
        ProductCategoryEntity productCategory = productCategoryModel.getByKey(categoryId, corpid);
        if (Objects.isNull(productCategory)) {
            return new ArrayList<>();
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("del", 0);
        String router = productCategory.getRouter();
        if (StringUtil.isEmpty(router)) {
            router = "|" + categoryId + "|";
        }
        param.put("routerLike", router);
        List<ProductCategoryEntity> productCategoryList = productCategoryModel.findEntitys(param);
        if (Objects.isNull(productCategoryList)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        List<Long> productCategoryIdIn = new ArrayList<>();
        productCategoryList.forEach(item->productCategoryIdIn.add(item.getId()));
        return productCategoryIdIn;
    }

    public void searchCheck(List<JSONObject> searchObjectList, ChartEntity chartEntity, ChartResultPojo chartResultPojo) throws XbbException {
        if (CollectionsUtil.isNotEmpty(searchObjectList)) {
            List<JSONObject> searchList = new ArrayList<>();
            for (JSONObject search : searchObjectList) {
                String attr = search.getString("attr");
                Integer businessType = search.getInteger("businessType");
                Object obj = search.get("value");
                String corpid = chartEntity.getCorpid();
                if (ProductEnum.CATEGORY_ID.getAttr().equals(attr) && Objects.equals(XbbRefTypeEnum.PRODUCT.getCode(), businessType)) {
                    if (obj instanceof JSONArray) {
                        JSONArray value = (JSONArray) obj;
                        if (CollectionUtils.isNotEmpty(value)) {
                            Object tempObject = value.get(0);
                            List<Long> subCategoryIdList = null;
                            if (tempObject instanceof Integer){
                                subCategoryIdList = getSubCategoryIdList(corpid, value.getInteger(0).longValue());
                            }else if (tempObject instanceof JSONObject){
                                subCategoryIdList = getSubCategoryIdList(corpid, value.getJSONObject(0).getInteger("id").longValue());
                            }
                            search.put("value", subCategoryIdList);
                            search.put("symbol",ConditionEnum.INCLUDE.getSymbol());
                        }
                    }
                    if (obj instanceof Integer) {
                        List<Long>  subCategoryIdList = getSubCategoryIdList(corpid,Long.valueOf(String.valueOf(obj)).longValue());
                        search.put("value", subCategoryIdList);
                        search.put("symbol",ConditionEnum.INCLUDE.getSymbol());
                    }
                }
                if (obj instanceof JSONArray) {
                    JSONArray value = (JSONArray) obj;
                    if (CollectionUtils.isNotEmpty(value)) {
                        if (ProductEnum.CATEGORY_ID.getAttr().equals(attr) && Objects.equals(XbbRefTypeEnum.PRODUCT.getCode(), businessType)) {
                            List<Long> subCategoryIdList = getSubCategoryIdList(corpid, value.getLong(0));
                            search.put("value", subCategoryIdList);
                        }
                        //跳过选了区间但是只给了一个值
                        if (value.size() == 2) {
                            JSONObject numericalJson = search.getJSONObject("numericalLimits");
                            if (StringUtil.isEmpty(value.getString(0))) {
                                if (numericalJson != null && numericalJson.get("min") != null) {
                                    value.set(0, numericalJson.get("min"));
                                    search.put("value", value);
                                }
                            } else if (StringUtil.isEmpty(value.getString(1))) {
                                if (numericalJson != null && numericalJson.get("max") != null) {
                                    value.add(1, numericalJson.get("max"));
                                    search.put("value", value);
                                }
                            }
                        }
                    }
                }
                searchList.add(search);
            }
            //处理全局筛选
            handleGlobalSearchRefactor(chartResultPojo,searchList);
            if (CollectionsUtil.isNotEmpty(searchList)) {
                chartEntity.setSearch(JSONArray.parseArray(JSON.toJSONString(searchList)));
            }
        }
    }

    /**
     * handleGlobalSearch()的重构方法,因为下面的方法是新增search的操作,改成修改的操作
     *
     * @param chartResultPojo 图表结果参数
     * @param searchList      检索的条件集合
     */
    public void handleGlobalSearchRefactor(ChartResultPojo chartResultPojo, List<JSONObject> searchList) {
        if (CollectionsUtil.isEmpty(searchList)) {
            return;
        }
        if (Objects.isNull(chartResultPojo.getGlobal())) {
            return;
        }
        if (!Objects.equals(ChartConstant.IS_GLOBAL, chartResultPojo.getGlobal())) {
            return;
        }
        for (JSONObject next : searchList) {
            Object attrType = next.get("attrType");
            Object global = next.get("global");
            if (Objects.isNull(global)) {
                continue;
            }
            if (!Objects.equals(ChartConstant.IS_GLOBAL, global)) {
                continue;
            }
            if (Objects.equals(attrType, "date")) {
                //时间筛选条件
                List<Integer> timeFilter = new ArrayList<>();
                timeFilter.add(chartResultPojo.getStartTime());
                timeFilter.add(chartResultPojo.getEndTime());
                next.put("symbol", ConditionEnum.RANGE.getSymbol());
                next.put("value", timeFilter);
            } else {
                List<Long> checkedDepIdIn = chartResultPojo.getCheckedDepIdIn();
                List<String> userIdIn = chartResultPojo.getUserIdIn();
                List<JSONObject> userAndDeptCheck = new ArrayList<>();
                Object fieldType = next.get("fieldType");
                if (Objects.equals(FieldTypeEnum.CREATORID.getType(), fieldType) ||
                        Objects.equals(FieldTypeEnum.USER.getType(), fieldType) ||
                        Objects.equals(FieldTypeEnum.USER_GROUP.getType(), fieldType) ||
                        Objects.equals(FieldTypeEnum.COUSERID.getType(), fieldType) ||
                        Objects.equals(FieldTypeEnum.OWNERID.getType(), fieldType)) {
                    if (CollectionsUtil.isNotEmpty(userIdIn)) {
                        userIdIn.forEach(userId -> {
                            JSONObject userSearch = new JSONObject();
                            userSearch.put("userId", userId);
                            userAndDeptCheck.add(userSearch);
                        });
                    }
                } else if (Objects.equals(FieldTypeEnum.DEPT.getType(), fieldType) ||
                        Objects.equals(FieldTypeEnum.DEPT_GROUP.getType(), fieldType) ||
                        Objects.equals(FieldTypeEnum.DEPARTMENTID.getType(), fieldType)) {
                    if (CollectionsUtil.isNotEmpty(checkedDepIdIn)) {
                        checkedDepIdIn.forEach(de -> {
                            JSONObject deptSearch = new JSONObject();
                            deptSearch.put("id", de);
                            deptSearch.put("value", de);
                            deptSearch.put("property", "dept");
                            userAndDeptCheck.add(deptSearch);
                        });
                    }
                }
                if (CollectionsUtil.isNotEmpty(userAndDeptCheck)) {
                    next.put("value", userAndDeptCheck);
                    next.put("symbol", ConditionEnum.IN.getSymbol());
                }
            }
        }
    }

    public void handleGlobalSearch(ChartResultPojo chartResultPojo, List<JSONObject> searchList) {
        if (CollectionsUtil.isNotEmpty(searchList)) {
            if (chartResultPojo.getGlobal() != null) {
                if (chartResultPojo.getGlobal().equals(ChartConstant.IS_GLOBAL)) {
                    List<JSONObject> globalSearchList = new ArrayList<>();
                    for (JSONObject next : searchList) {
                        Object attrType = next.get("attrType");
                        if (next.get("global") != null) {
                            if (next.get("global").equals(ChartConstant.IS_GLOBAL)) {
                                if (Objects.equals(attrType, "date")) {
                                    String search4GlobalTime;
                                    //时间筛选条件
                                    List<Integer> timeFilter = new ArrayList<>();
                                    timeFilter.add(chartResultPojo.getStartTime());
                                    timeFilter.add(chartResultPojo.getEndTime());
                                    search4GlobalTime = next.toString();
                                    JSONObject jsonObject = JSONObject.parseObject(search4GlobalTime);
                                    jsonObject.put("symbol", ConditionEnum.RANGE.getSymbol());
                                    jsonObject.put("value", timeFilter);
                                    globalSearchList.add(jsonObject);
                                } else {
                                    List<Long> checkedDepIdIn = chartResultPojo.getCheckedDepIdIn();
                                    List<String> userIdIn = chartResultPojo.getUserIdIn();
                                    List<JSONObject> userAndDeptCheck = new ArrayList<>();
                                    JSONObject search4GlobalUser;
                                    String search4GlobalUser1 = next.toString();
                                    search4GlobalUser = JSONObject.parseObject(search4GlobalUser1);
                                    Object fieldType = next.get("fieldType");
                                    if (Objects.equals(FieldTypeEnum.CREATORID.getType(), fieldType) ||
                                            Objects.equals(FieldTypeEnum.USER.getType(), fieldType) ||
                                            Objects.equals(FieldTypeEnum.USER_GROUP.getType(), fieldType) ||
                                            Objects.equals(FieldTypeEnum.COUSERID.getType(), fieldType) ||
                                            Objects.equals(FieldTypeEnum.OWNERID.getType(), fieldType)) {
                                        if (CollectionsUtil.isNotEmpty(userIdIn)) {
                                            userIdIn.forEach(x -> {
                                                JSONObject userSearch = new JSONObject();
                                                userSearch.put("userId",x);
                                                //JSONObject userSear = JSONObject.parseObject(String.valueOf(userVO));
                                                userAndDeptCheck.add(userSearch);
                                            });
                                        }
                                    } else if (Objects.equals(FieldTypeEnum.DEPT.getType(), fieldType) ||
                                            Objects.equals(FieldTypeEnum.DEPT_GROUP.getType(), fieldType) ||
                                            Objects.equals(FieldTypeEnum.DEPARTMENTID.getType(), fieldType)) {
                                        if (CollectionsUtil.isNotEmpty(checkedDepIdIn)) {
                                            checkedDepIdIn.forEach(de -> {
                                                JSONObject deptSearch = new JSONObject();
                                                deptSearch.put("id",de);
                                                deptSearch.put("value",de);
                                                deptSearch.put("property","dept");
                                                userAndDeptCheck.add(deptSearch);
                                            });
                                        }
                                    }
                                    if (CollectionsUtil.isNotEmpty(userAndDeptCheck)) {
                                        search4GlobalUser.put("value", userAndDeptCheck);
                                        search4GlobalUser.put("symbol", ConditionEnum.IN.getSymbol());
                                        globalSearchList.add(search4GlobalUser);
                                    }
                                }
                            }
                        }
                    }
                    if (CollectionUtils.isNotEmpty(globalSearchList)) {
                        searchList.addAll(globalSearchList);
                    }
                }
            }
        }
    }

    /**
     * 子表单列表字段解析
     * @param headAttrMap 表头字段对应
     * @param attrToValuesMap 需解析值集合对应attr映射
     * @param chartEntity chart实体
     * @param entityList 结果集
     * @throws XbbException error
     * @author zhouwq
     * @date 2020/10/15 14:10
     */
    public void analysisSubFormData(Map<String, ChartFieldAttrPojo> headAttrMap, Map<String, List<String>> attrToValuesMap, ChartEntity chartEntity, List<? extends PaasFormSubDataEntity> entityList, BaseDTO baseDTO) throws XbbException{
        //字段解析
        for (Map.Entry<String, ChartFieldAttrPojo> entry : headAttrMap.entrySet()) {
            String attr = entry.getKey();
            ChartFieldAttrPojo field = entry.getValue();
            List<String> valueObjList = attrToValuesMap.get(attr);
            List<String> valueResult = new ArrayList<>();
            if (valueObjList == null || valueObjList.size() == 0) {
                continue;
            }
            Integer fieldType = field.getFieldType();
            Integer comboType = field.getComboType();
            //数组类型字段解析处理
            if (Objects.equals(fieldType, FieldTypeEnum.USER_GROUP.getType()) || Objects.equals(fieldType, FieldTypeEnum.DEPT_GROUP.getType())
                    || Objects.equals(fieldType, FieldTypeEnum.CHECKBOX_GROUP.getType()) || Objects.equals(fieldType, FieldTypeEnum.COMBO_CHECK.getType())) {
                for (String e : valueObjList) {
                    String v1 = e.replaceAll("\\[", "").replaceAll("]", "").replaceAll("\"", "");
                    valueResult.add(v1);
                }
            } else {
                valueResult = valueObjList;
            }
            // 关联数据不用解析，存的就是解析完的值
            if (ComboTypeEnum.LINKFORM.getType().equals(comboType)) {
                for (PaasFormSubDataEntity e : entityList) {
                    StringBuilder newValue = new StringBuilder();
                    JSONObject dataObj = e.getData();
                    Object val = dataObj.get(attr);
                    if (val instanceof List) {
                        JSONArray oldVal = (JSONArray) val;
                        for (Object str : oldVal) {
                            newValue.append(str).append(",");
                        }
                    } else {
                        if (val != null) {
                            newValue.append(val);
                        }
                    }
                    //最终结果字符串
                    String str = newValue.toString();
                    if (str.endsWith(",")) {
                        str = str.substring(0, str.length() - 1);
                    }
                    dataObj.put(attr, str);
                }
            } else {
                Map<String, String> parseMap =  valueListAnalysis(field, chartEntity.getCorpid(), valueResult, chartEntity, false, null, false, baseDTO,null);
                for (PaasFormSubDataEntity e : entityList) {
                    StringBuilder newValue = new StringBuilder();
                    JSONObject dataObj = e.getData();
                    Object old = dataObj.get(attr);
                    if (old instanceof List) {
                        JSONArray oldArray = (JSONArray) old;
                        for (Object str : oldArray) {
                            if (newValue.length() != BasicConstant.ZERO){
                                newValue.append(StringConstant.COMMA);
                            }
                            newValue.append(Optional.ofNullable(parseMap.get(str.toString())).orElse(str.toString()));
                        }
                    } else {
                        String oldValue = dataObj.getString(attr);
                        if (oldValue != null) {
                            newValue.append(parseMap.get(oldValue));
                        }
                    }
                    //最终结果字符串
                    String str = newValue.toString();
                    if (str.endsWith(",")) {
                        str = str.substring(0, str.length() - 1);
                    }
                    dataObj.put(attr, str);
                }
            }
        }
    }

    public boolean checkDataSecurity(Integer chartType, ChartPenetrateResultDTO chartResultDTO) {
        if (chartType.equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())) {
            List<JSONObject> valueList = chartResultDTO.getPenetrateCondition();
            for (JSONObject jsonObject : valueList) {
                if (StringUtil.isEmpty(jsonObject.toJSONString())) {
                    return false;
                } else if (!jsonObject.containsKey("originValue") || !jsonObject.containsKey("value")
                        || !jsonObject.containsKey("key") || !jsonObject.containsKey("formId")) {
                    return false;
                }
            }
        } else {
            if (Objects.isNull(chartResultDTO.getSelectedAxis())
                    && Objects.isNull(chartResultDTO.getSelectedLegend())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 统计表穿透数据解析
     *
     * @param conditionList
     * @param filterList
     * @param formIdToBusinessTypeMap
     * @author zyy
     * @date 2022/12/12
     * @version v1.0
     */
    public void parseTableCondition(List<JSONObject> conditionList, List<JSONObject> filterList, Map<Long, Integer> formIdToBusinessTypeMap,String flag) {
        for (JSONObject condition : conditionList) {
            JSONObject filter = new JSONObject();
            String key = condition.getString(FieldAttrConstant.KEY);
            String[] keySplit = key.split(SymbolConstant.AND);
            if (keySplit.length == 2) {
                filter.put(FieldAttrConstant.ATTR, keySplit[0]);
                filter.put(FieldAttrConstant.FIELD_TYPE, keySplit[1]);
            } else {
                filter.put(FieldAttrConstant.ATTR, keySplit[1]);
                filter.put(FieldAttrConstant.FIELD_TYPE, keySplit[2]);
            }
            if (condition.getString(FieldAttrConstant.DATE_GROUP_TYPE) != null) {
                filter.put(FieldAttrConstant.DATE_GROUP_TYPE, condition.getString(FieldAttrConstant.DATE_GROUP_TYPE));
            }
            parsePenetrateCondition(filter.getInteger(FieldAttrConstant.FIELD_TYPE), filter, condition.get(FieldAttrConstant.ORIGIN_VALUE));
            Long formId = condition.getLongValue(FieldAttrConstant.FORMID);
            filter.put(FieldAttrConstant.FORMID, formId);
            filter.put(FieldAttrConstant.BUSINESS_TYPE, formIdToBusinessTypeMap.get(formId));
            filter.put(flag, BasicConstant.ONE);
            filterList.add(filter);
        }
    }

    public void parsePenetrateCondition(Integer type, JSONObject jsonObject, Object axisKey) {
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(type);
        if (fieldTypeEnum == null) {
            jsonObject.put("symbol", ConditionEnum.EQUAL.getSymbol());
            if (axisKey != null) {
                jsonObject.put("value", axisKey);
            } else {
                jsonObject.put("value", jsonObject.get("originValue"));
            }
            return;
        }
        switch (fieldTypeEnum) {
            case ADDTIME:
            case UPDATETIME:
            case DATETIME:
            case CLOSETIME:
            case ENDTIME:
            case BIRTHDAY:
                String axisKeyString = axisKey.toString();
                if (StringUtil.isEmpty(axisKeyString)) {
                    jsonObject.put("symbol", ConditionEnum.EMPTY.getSymbol());
                    jsonObject.put("value", new ArrayList<>());
                    break;
                }
                customHelp.dealTimeRangeLong(jsonObject, axisKeyString);
                break;
            default:
                jsonObject.put("symbol", ConditionEnum.EQUAL.getSymbol());
                if (axisKey != null) {
                    if (Objects.equals(axisKey, "")) {
                        jsonObject.put("symbol", ConditionEnum.EMPTY.getSymbol());
                    }
                    jsonObject.put("value", axisKey);
                } else {
                    if (jsonObject.get("originValue") == null || Objects.equals(jsonObject.get("originValue"), "")) {
                        jsonObject.put("symbol", ConditionEnum.EMPTY.getSymbol());
                    }
                    jsonObject.put("value", jsonObject.get("originValue"));
                }
                break;
        }
    }

    /**
     * 映射数据的展示值
     *
     * @param analysisMap 映射容器  key为原始数据  value为映射后的数据
     * @param originValue 原始数据
     * @param fieldAttrPojo 当前映射的字段实体
     * @return java.lang.String
     * @author zyy
     * @date 2022/11/8
     * @version v1.0
     */
    public String analysisResultValue(Map<String, String> analysisMap, String originValue, FieldAttrPojo fieldAttrPojo) {
        //无映射关系时，返回原始数据
        if(!analysisMap.containsKey(originValue)){
            return originValue;
        }

        String analysisResult = analysisMap.get(originValue);
        Integer fieldType = fieldAttrPojo.getFieldType();
        //非阶段推进器字段直接映射后的数据
        boolean isStage = Objects.equals(FieldTypeEnum.getFieldTypeEnum(fieldType), FieldTypeEnum.STAGE_THRUSTER);
        if(!isStage){
            return analysisResult;
        }

        //阶段推进器字段需要判断是否需要拼接文案提示（未启用的阶段需要拼接`历史版本`）
        List<ItemPoJo> attrPojoItems = fieldAttrPojo.getItems();
        if(CollectionUtils.isEmpty(attrPojoItems)){
            return analysisResult;
        }

        if(attrPojoItems.stream().noneMatch(itemPoJo -> Objects.equals(itemPoJo.getValue(), originValue))){
            analysisResult += StringConstant.NOT_ENABLED;
            //统计图需要
            analysisMap.put(originValue,analysisResult);
        }
        return analysisResult;
    }

    /**
     * 系列字段为下拉类型时手动调整legendKeys的顺序
     *
     * @param legendKeys
     * @param legendAttr
     * @return java.util.List<java.lang.String>
     * @author zyy
     * @date 2022/11/17
     * @version v1.0
     */
    public List<String> reOrderSeries(List<String> legendKeys, FieldAttrPojo legendAttr) {
        // （启用的值 + "" + 未启用的值）
        List<ItemPoJo> itemPoJos = legendAttr.getItems();
        if (CollectionUtils.isEmpty(itemPoJos)){
            return legendKeys;
        }
        List<String> resultStrList = new ArrayList<>();
        for (ItemPoJo itemPoJo : itemPoJos) {
            String itemValue = String.valueOf(itemPoJo.getValue());
            boolean removeIf = legendKeys.removeIf(str -> Objects.equals(str, itemValue));
            if(removeIf){
                resultStrList.add(itemValue);
            }
        }
        // 固定 "" 的位置 （避免在legendKeys中 "" 不是在第一个）
        if(legendKeys.removeIf(str -> Objects.equals(str, ""))){
            resultStrList.add("");
        }
        resultStrList.addAll(legendKeys);
        return resultStrList;
    }
    /**
     * 处理钻取操作之后展示字段的时间格式（y-m、y、y-q等等）
     * @param disArray 展示字段
     * @param chartEntity 图表数据
     * @param chartResultDTO 获取图表穿透参数
     * @author 晨泓
     * @update by zcp：合并4.60分支时从原位置迁移至该help
     */
    public void dealDisplayAttrTimeFormat(JSONArray disArray, ChartEntity chartEntity, ChartPenetrateResultDTO chartResultDTO) {
        if (CollectionsUtil.isEmpty(chartResultDTO.getPenetrateCondition()) || CollectionsUtil.isEmpty(disArray)) {
            return;
        }
        for (int i = 0; i < disArray.size(); i++) {
            JSONObject jsonObject = disArray.getJSONObject(i);
            Integer fieldType = jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE);
            Integer formId = jsonObject.getInteger(FieldAttrConstant.FORMID);

            // 此处代码用于钻取时间之后的穿透时间类型不同的处理,比如从年 钻取到年季度，这个时候点击年穿透，应该展现的是格式是年
            if (EsHelper.isDateTimeByFieldType(fieldType)) {
                String attr = jsonObject.getString(FieldAttrConstant.ATTR);
                for (JSONObject object : chartResultDTO.getPenetrateCondition()) {
                    if (EsUtil.getSingle(chartEntity)) {
                        String attr1 = object.getString("key").split("&")[0];
                        Integer formId1 = object.getInteger(FieldAttrConstant.FORMID);
                        if (Objects.equals(attr1, attr) && Objects.equals(formId, formId1)) {
                            jsonObject.put(FieldAttrConstant.DATE_GROUP_TYPE, object.getString(FieldAttrConstant.DATE_GROUP_TYPE));
                            jsonObject.put(FieldAttrConstant.DATE_TYPE, object.getString(FieldAttrConstant.DATE_GROUP_TYPE));
                        }
                    } else {
                        String attr1 = object.getString("outKey").split("&")[0];
                        Integer formId1 = object.getInteger(FieldAttrConstant.FORMID);
                        if (Objects.equals(attr1, attr) && Objects.equals(formId, formId1)) {
                            jsonObject.put(FieldAttrConstant.DATE_GROUP_TYPE, object.getString(FieldAttrConstant.DATE_GROUP_TYPE));
                            jsonObject.put(FieldAttrConstant.DATE_TYPE, object.getString(FieldAttrConstant.DATE_GROUP_TYPE));
                        }
                    }
                }
            }
        }

    }
    /**
     * 图表联动入参解析
     *
     * @param chartResultDTO 图表渲染入参实体
     * @param linkedChart 被联动图表
     * @author zyy
     * @date 2022/12/12
     * @version v1.0
     */
    public void analysisLinkage(ChartResultDTO chartResultDTO, ChartEntity linkedChart, List<PaasFormExplainEntity> explainEntityList) throws XbbException {
        JSONObject linkage = chartResultDTO.getLinkage();
        if(linkParamFilter(linkage)){
            return;
        }
        //联动数据不为空时需要校验联动权限
        if(linkageHelp.linkageBaseFilter(chartResultDTO.getLoginUser().getPermSet(), chartResultDTO.getCorpid())){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224097);
        }
        //解析数据并生成对应的filter
        JSONArray filterArray = linkedChart.getFilter();
        List<JSONObject> filterList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(filterArray)) {
            filterList = filterArray.toJavaList(JSONObject.class);
        }
        ChartEntity linkageChart = linkage.getJSONObject(StringConstant.CHART_ENTITY).toJavaObject(ChartEntity.class);
        if(Objects.equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode(),linkageChart.getChartType())){
            //统计表数据解析
            List<JSONObject> tableConditionList = linkage.getJSONArray(StringConstant.TABLE_CONDITION).toJavaList(JSONObject.class);
            Map<Long,Integer> formIdToBusinessTypeMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            explainEntityList.forEach(e -> formIdToBusinessTypeMap.put(e.getFormId(), e.getBusinessType()));
            parseTableCondition(tableConditionList,filterList,formIdToBusinessTypeMap,StringConstant.LINKAGE_FLAG);
        }else{
            //统计图解析
            List<JSONObject> chartConditionList = linkage.getJSONArray(StringConstant.CHART_CONDITION).toJavaList(JSONObject.class);
            JSONObject chartCondition = chartConditionList.get(0);
            parseChartCondition(chartCondition.getString(StringConstant.SELECTED_AXIS),chartCondition.getString(StringConstant.SELECTED_LEGEND),linkageChart,filterList,StringConstant.LINKAGE_FLAG);
        }
        linkedChart.setFilter(JSONArray.parseArray(filterList.toString()));
    }

    /**
     * 图表渲染时联动入参校验
     *
     * @param linkage 联动数据
     * @return boolean true-过滤 , false-不过滤
     * @author zyy
     * @date 2022/12/13
     * @version v1.0
     */
    public boolean linkParamFilter(JSONObject linkage) {
        if(MapUtils.isEmpty(linkage)){
            return true;
        }
        JSONArray tableConditionArray = linkage.getJSONArray(StringConstant.TABLE_CONDITION);
        JSONArray chartConditionArray = linkage.getJSONArray(StringConstant.CHART_CONDITION);
        return CollectionUtils.isEmpty(tableConditionArray) && CollectionUtils.isEmpty(chartConditionArray);
    }

    /**
     * 统计图解析生成filter数据
     *
     * @param xAxisValue 分类的值
     * @param legendValue 系列的值
     * @param chartEntity 图表实体
     * @param filterList 查询条件数组
     * @param flag 解析标记 （穿透、联动）
     * @author zyy
     * @date 2022/12/12
     * @version v1.0
     */
    public void parseChartCondition(String xAxisValue, String legendValue, ChartEntity chartEntity,List<JSONObject> filterList,String flag) {
        JSONObject xAxisField = chartEntity.getChartClassify().getJSONObject(BasicConstant.ZERO);
        JSONObject legendField = null;
        if(CollectionUtils.isNotEmpty(chartEntity.getChartSeries())){
            legendField = chartEntity.getChartSeries().getJSONObject(BasicConstant.ZERO);
        }
        //统计图的传参层级为 分类 -> 系列
        if (Objects.nonNull(xAxisValue)) {
            parsePenetrateCondition(xAxisField.getInteger(FieldAttrConstant.FIELD_TYPE), xAxisField, xAxisValue);
            if(StringUtils.isNotBlank(flag)){
                xAxisField.put(flag, BasicConstant.ONE);
            }
            filterList.add(xAxisField);
            if (Objects.nonNull(legendField) && Objects.nonNull(legendValue)) {
                parsePenetrateCondition(legendField.getInteger(FieldAttrConstant.FIELD_TYPE), legendField, legendValue);
                if(StringUtils.isNotBlank(flag)){
                    legendField.put(flag, BasicConstant.ONE);
                }
                filterList.add(legendField);
            }
        }
    }

    /**
     * 图表数据的缓存key
     *
     * @param chartEntity
     * @param chartResultPojo
     * @param diyResultDTO
     * @return java.lang.String
     * @author zyy
     * @date 2022/12/14
     * @version v1.0
     */
    public String getChartCacheKey(ChartEntity chartEntity, ChartResultPojo chartResultPojo, DiyResultDTO diyResultDTO) {
        //eg：corpid_userId_chartId_diyResultDTO加密后的字符串
        StringBuffer key = new StringBuffer();
        key.append(chartEntity.getCorpid())
                .append(StringConstant.UNDER_LINE)
                .append(chartResultPojo.getUserId())
                .append(StringConstant.UNDER_LINE)
                .append(chartEntity.getId())
                .append(StringConstant.UNDER_LINE)
                .append(DigestUtil.Encrypt(diyResultDTO.toString(), "SHA-256"));
        return key.toString();
    }

    /**
     * 获取没有设置穿透显示字段时的穿透点击的那个表头字段
     *
     * @param chartResultDTO 前端传参
     * @param chartEntity    图表实体
     * @return 穿透时点击的那个字段
     */
    public JSONObject getPenetrateClickField(ChartPenetrateResultDTO chartResultDTO, ChartEntity chartEntity) {

        List<JSONObject> penetrateCondition = chartResultDTO.getPenetrateCondition();
        if (CollectionsUtil.isEmpty(penetrateCondition)) {
            return null;
        }
        // 需要展示的穿透字段
        JSONObject jsonObject = penetrateCondition.get(penetrateCondition.size() - BasicConstant.ONE);

        // 匹配目标的源数据
        JSONArray jsonArray = new JSONArray();

        // 加入已经钻取的层级字段
        Map<String, ChartDrillInfoPojo> drill = chartResultDTO.getDrill();
        if (!Objects.isNull(drill) && drill.size() > BasicConstant.ZERO) {
            addDrillField(jsonArray, drill, DrillFieldEnum.ROW_GROUP_ATTR.getAlias());
            addDrillField(jsonArray, drill, DrillFieldEnum.COL_GROUP_ATTR.getAlias());
            addDrillField(jsonArray, drill, DrillFieldEnum.CHART_CLASSIFY.getAlias());
            addDrillField(jsonArray, drill, DrillFieldEnum.CHART_SERIES.getAlias());
        }

        // 加入行列分组字段
        JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
        JSONArray colGroupAttr = chartEntity.getColGroupAttr();
        jsonArray.fluentAddAll(rowGroupAttr).fluentAddAll(colGroupAttr);

        return getMatchClickField(jsonObject, jsonArray, chartEntity);
    }

    /**
     * 把钻取字段也添加到筛选穿透点击字段的集合中
     *
     * @param jsonArray  穿透点击字段的集合
     * @param drill      钻取信息
     * @param drillField 钻取字段 对应 DrillFieldEnum枚举
     */
    private void addDrillField(JSONArray jsonArray, Map<String, ChartDrillInfoPojo> drill, String drillField) {
        ChartDrillInfoPojo drillInfoPojo = drill.get(drillField);
        if (Objects.isNull(drillInfoPojo)) {
            return;
        }
        List<FieldAttrPojo> drillCondition = drillInfoPojo.getDrillCondition();
        if (CollectionsUtil.isEmpty(drillCondition)) {
            return;
        }
        JSONArray drillJsonArray = JSON.parseArray(JSON.toJSONString(drillCondition));
        jsonArray.addAll(drillJsonArray);
    }

    /**
     * 获取匹配的穿透点击字段
     *
     * @param jsonObject 穿透条件的最后一个值
     * @param jsonArray  行列分组、分类系列、以及钻取的新字段
     * @param chartEntity 图表实体
     * @return 穿透点击的字段
     */
    private JSONObject getMatchClickField(JSONObject jsonObject, JSONArray jsonArray, ChartEntity chartEntity) {
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject fieldJson = jsonArray.getJSONObject(i);

            if (matchClickField(jsonObject, fieldJson, chartEntity)) {
                return fieldJson;
            }
        }

        return null;
    }

    /**
     * 拿到当前图表的字段与点击字段进行一个匹配
     *
     * @param jsonObject  点击字段
     * @param fieldJson   图表字段
     * @param chartEntity 图表实体
     * @return 匹配结果，成功就是true，失败就是false
     */
    private boolean matchClickField(JSONObject jsonObject, JSONObject fieldJson, ChartEntity chartEntity) {
        String key = jsonObject.getString(ChartStatisticsConstant.KEY);
        String[] keySplit = key.split(ChartStatisticsConstant.AND);
        String attr;
        int fieldType;
        if (keySplit.length == BasicConstant.TWO) {
            fieldType = Integer.parseInt(keySplit[1]);
        } else {
            fieldType = Integer.parseInt(keySplit[2]);
        }
        String outKey = jsonObject.getString(ChartStatisticsConstant.OUT_KEY);
        if (StringUtil.isEmpty(outKey)) {
            attr = keySplit[0];
        } else {
            attr = outKey.split(ChartStatisticsConstant.AND)[0];
        }
        String dateGroupType = jsonObject.getString(FieldAttrConstant.DATE_GROUP_TYPE);

        // 目前的图表的字段信息   单表的时候是没有nowOriginalAttr为null
        String nowAttr = fieldJson.getString(FieldAttrConstant.ATTR);

        boolean attrFlag = Objects.equals(nowAttr, attr);

        if (EsHelper.isDateTimeByFieldType(fieldType)) {
            return attrFlag && Objects.equals(dateGroupType, fieldJson.getString(FieldAttrConstant.DATE_GROUP_TYPE));
        }

        return attrFlag;
    }

    /**
     * 统计图穿透 创建filter
     *  @param chartResultDTO 传参
     * @param chartEntity    图表信息
     * @param filterList     过滤器
     */
    public void chartPenetrateCondition(ChartPenetrateResultDTO chartResultDTO, ChartEntity chartEntity, List<JSONObject> filterList) {
        String xAxisKeys = chartResultDTO.getSelectedAxis();
        String legendKeys = chartResultDTO.getSelectedLegend();
        JSONArray xAxisArray = chartEntity.getChartClassify();
        JSONArray legendArray = chartEntity.getChartSeries();
        dealXAxisOrLegendArray(filterList, xAxisKeys, legendKeys, xAxisArray, legendArray);

        chartEntity.setFilter(JSONArray.parseArray(filterList.toString()));
    }

    /**
     * 处理图的x轴和y轴穿透的参数
     *
     * @param filterList  过滤器集合
     * @param xAxisKeys   分类的key值,对应sql查询时候传的value
     * @param legendKeys  系列的key值,对应sql查询时候传的value
     * @param xAxisArray  图的分类属性
     * @param legendArray 图的系列属性
     */
    private void dealXAxisOrLegendArray(List<JSONObject> filterList, String xAxisKeys, String legendKeys, JSONArray xAxisArray, JSONArray legendArray) {
        if (xAxisKeys != null) {
            JSONObject xAxisObj = xAxisArray.getJSONObject(0);
            parsePenetrateCondition(xAxisObj.getInteger("fieldType"), xAxisObj, xAxisKeys);
            xAxisObj.put("penetrateFlag", 1);
            filterList.add(xAxisObj);
            if (legendKeys != null && legendArray != null && legendArray.size() > 0) {
                JSONObject legendObj = legendArray.getJSONObject(0);
                parsePenetrateCondition(legendObj.getInteger("fieldType"), legendObj, legendKeys);
                legendObj.put("penetrateFlag", 1);
                filterList.add(legendObj);
            }
        }
    }

    /**
     * 此方法用于修改统计图钻取之后最新的分类和系列，防止钻取之后的穿透失效
     *
     * @param chartResultPojo 图表结果参数
     * @param chartEntity     图表实体
     */
    public void updateChartClassifyAndSeries(ChartResultPojo chartResultPojo, ChartEntity chartEntity) {
        if (Objects.isNull(chartResultPojo)){
            return;
        }
        DrillResultPojo drillResultPojo = chartResultPojo.getDrillResultPojo();
        if (Objects.isNull(drillResultPojo)){
            return;
        }
        Map<Long, DrillResultChartInfoPojo> resultChartInfoMap = drillResultPojo.getResultChartInfoMap();
        if (Objects.isNull(resultChartInfoMap) || resultChartInfoMap.size() == BasicConstant.ZERO){
            return;
        }
        DrillResultChartInfoPojo drillResultChartInfoPojo = resultChartInfoMap.get(chartEntity.getId());
        if (Objects.isNull(drillResultChartInfoPojo)){
            return;
        }
        Map<String, DrillResultChartFieldInfoPojo> chartFieldInfoMap = drillResultChartInfoPojo.getChartFieldInfoMap();
        if (Objects.isNull(chartFieldInfoMap) || chartFieldInfoMap.size() == BasicConstant.ZERO){
            return;
        }
        DrillResultChartFieldInfoPojo classifyDrillResultChartFieldInfoPojo = chartFieldInfoMap.get(DrillFieldEnum.CHART_CLASSIFY.getAlias());
        dealClassifyOrSeries(chartEntity, classifyDrillResultChartFieldInfoPojo);

        DrillResultChartFieldInfoPojo seriesDrillResultChartFieldInfoPojo = chartFieldInfoMap.get(DrillFieldEnum.CHART_SERIES.getAlias());
        dealClassifyOrSeries(chartEntity, seriesDrillResultChartFieldInfoPojo);
    }

    /**
     * 处理钻去之后最新的分类或者系列
     *
     * @param chartEntity                   图表实体
     * @param drillResultChartFieldInfoPojo 钻取参数
     */
    private void dealClassifyOrSeries(ChartEntity chartEntity, DrillResultChartFieldInfoPojo drillResultChartFieldInfoPojo) {
        if (Objects.nonNull(drillResultChartFieldInfoPojo)) {
            FieldAttrPojo goalDrillField = drillResultChartFieldInfoPojo.getGoalDrillField();
            JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(goalDrillField));
            List<JSONObject> list = new ArrayList<>();
            list.add(jsonObject);
            ReflectHelper.valueSet(chartEntity, drillResultChartFieldInfoPojo.getChartField(), JSON.parseArray(JSON.toJSONString(list)));
        }
    }

}
